Big Fix commit:
+ Added new Clients for CRM/Products + Removed old fake coming-soon pages + Added combineUrl and AppSettingsConfig with proxyUrl + Added new fields to modules info on Server + Fixed work with icon and image urls + Added CRM/Projects to nginx/onlyoffice.conf + Applied combineUrl in studio links + Added and applied "id" field in package.json of all Clients + Added new bat files CrmClient.bat and ProjectsClient.bat + Fixed ProductClassName for Files
2
build/run/CrmClient.bat
Normal file
@ -0,0 +1,2 @@
|
||||
echo "RUN ASC.Web.CRM"
|
||||
call set BROWSER=none&&npm start --prefix ../../products/ASC.CRM/Client
|
2
build/run/ProjectsClient.bat
Normal file
@ -0,0 +1,2 @@
|
||||
echo "RUN ASC.Web.Projects"
|
||||
call set BROWSER=none&&npm start --prefix ../../products/ASC.Projects/Client
|
@ -7,20 +7,29 @@ namespace ASC.Api.Core
|
||||
public class Module
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string AppName { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Link { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
public string Link { get; set; }
|
||||
|
||||
public string IconUrl { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
public string HelpUrl { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool IsPrimary { get; set; }
|
||||
|
||||
public Module(Product product)
|
||||
{
|
||||
Id = product.ProductID;
|
||||
AppName = product.ProductClassName;
|
||||
Title = product.Name;
|
||||
Description = product.Description;
|
||||
IconUrl = product.Context.IconFileName;
|
||||
ImageUrl = product.Context.LargeIconFileName;
|
||||
Link = product.StartURL;
|
||||
IsPrimary = product.IsPrimary;
|
||||
HelpUrl = product.HelpURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,33 +270,94 @@ server {
|
||||
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
|
||||
}
|
||||
}
|
||||
|
||||
location ~* (/crm|/mail/|/calendar|/projects|/talk) {
|
||||
#rewrite products/people/(.*) /$1 break;
|
||||
proxy_pass http://localhost:5001;
|
||||
|
||||
location ~* /crm {
|
||||
#rewrite products/crm/(.*) /$1 break;
|
||||
proxy_pass http://localhost:5014;
|
||||
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
|
||||
|
||||
location ~* /(sockjs-node|locales) {
|
||||
rewrite products/people(.*)/(sockjs-node|locales)/(.*) /$2/$3 break;
|
||||
location ~* /sockjs-node {
|
||||
rewrite products/crm(.*)/sockjs-node/(.*) /$2/$3 break;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_pass http://localhost:5001;
|
||||
|
||||
|
||||
proxy_pass http://localhost:5014;
|
||||
|
||||
proxy_redirect off;
|
||||
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
location ~* /locales {
|
||||
proxy_pass http://localhost:5014;
|
||||
proxy_redirect off;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
location ~* /(manifest.json|service-worker.js|appIcon.png|bg-error.png) {
|
||||
root $public_root;
|
||||
try_files /$basename /index.html =404;
|
||||
}
|
||||
|
||||
location ~* (/httphandlers/filehandler.ashx|ChunkedUploader.ashx) {
|
||||
proxy_pass http://localhost:5007;
|
||||
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
|
||||
}
|
||||
}
|
||||
|
||||
location ~* /projects {
|
||||
#rewrite products/projects/(.*) /$1 break;
|
||||
proxy_pass http://localhost:5015;
|
||||
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
|
||||
|
||||
location ~* /sockjs-node {
|
||||
rewrite products/projects(.*)/sockjs-node/(.*) /$2/$3 break;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_pass http://localhost:5015;
|
||||
|
||||
proxy_redirect off;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
location ~* /locales {
|
||||
proxy_pass http://localhost:5015;
|
||||
proxy_redirect off;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
location ~* /(manifest.json|service-worker.js|appIcon.png|bg-error.png) {
|
||||
root $public_root;
|
||||
try_files /$basename /index.html =404;
|
||||
}
|
||||
|
||||
location ~* (/httphandlers/filehandler.ashx|ChunkedUploader.ashx) {
|
||||
proxy_pass http://localhost:5007;
|
||||
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
location /apisystem {
|
||||
|
@ -20,6 +20,14 @@
|
||||
"name": "🚀 @appserver/people",
|
||||
"path": "products\\ASC.People\\Client"
|
||||
},
|
||||
{
|
||||
"name": "🚀 @appserver/crm",
|
||||
"path": "products\\ASC.Crm\\Client"
|
||||
},
|
||||
{
|
||||
"name": "🚀 @appserver/projects",
|
||||
"path": "products\\ASC.Projects\\Client"
|
||||
},
|
||||
{
|
||||
"name": "🚀 @appserver/studio",
|
||||
"path": "web\\ASC.Web.Client"
|
||||
|
@ -8,7 +8,9 @@
|
||||
"web/ASC.Web.Client",
|
||||
"web/ASC.Web.Editor",
|
||||
"products/ASC.People/Client",
|
||||
"products/ASC.Files/Client"
|
||||
"products/ASC.Files/Client",
|
||||
"products/ASC.CRM/Client",
|
||||
"products/ASC.Projects/Client"
|
||||
],
|
||||
"scripts": {
|
||||
"wipe": "rimraf node_modules yarn.lock web/**/node_modules products/**/node_modules",
|
||||
|
@ -1,16 +1,30 @@
|
||||
import axios from "axios";
|
||||
import config from "../package.json";
|
||||
//import history from "../history";
|
||||
import { AppServerConfig } from "../constants";
|
||||
import { combineUrl } from "../utils";
|
||||
|
||||
const baseURL = `${window.location.origin}/${config.api.url}`;
|
||||
const apiTimeout = config.api.timeout;
|
||||
const { proxyURL, apiPrefixURL, apiTimeout } = AppServerConfig;
|
||||
const origin = window.location.origin;
|
||||
|
||||
const apiBaseURL = combineUrl(origin, proxyURL, apiPrefixURL);
|
||||
const loginURL = combineUrl(proxyURL, "/login");
|
||||
const paymentsURL = combineUrl(proxyURL, "/payments");
|
||||
|
||||
window.AppServer = {
|
||||
origin,
|
||||
proxyURL,
|
||||
apiPrefixURL,
|
||||
apiBaseURL,
|
||||
apiTimeout,
|
||||
loginURL,
|
||||
paymentsURL,
|
||||
};
|
||||
|
||||
/**
|
||||
* @description axios instance for ajax requests
|
||||
*/
|
||||
|
||||
const client = axios.create({
|
||||
baseURL: baseURL,
|
||||
baseURL: apiBaseURL,
|
||||
responseType: "json",
|
||||
timeout: apiTimeout, // default is `0` (no timeout)
|
||||
});
|
||||
@ -25,11 +39,11 @@ client.interceptors.response.use(
|
||||
switch (true) {
|
||||
case error.response.status === 401:
|
||||
setWithCredentialsStatus(false);
|
||||
window.location.href = "/login";
|
||||
window.location.href = loginURL;
|
||||
break;
|
||||
case error.response.status === 402:
|
||||
if (!window.location.pathname.includes("payments")) {
|
||||
window.location.href = "/payments";
|
||||
window.location.href = paymentsURL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { request } from "../client";
|
||||
import { combineUrl } from "../../utils";
|
||||
import { AppServerConfig } from "../../constants";
|
||||
const { proxyURL } = AppServerConfig;
|
||||
|
||||
export function getModulesList() {
|
||||
return request({
|
||||
@ -11,8 +14,8 @@ export function getModulesList() {
|
||||
const newModules = workingModules.map((m) => {
|
||||
return {
|
||||
...m,
|
||||
iconUrl: m.link + "images/icon.svg",
|
||||
imageUrl: m.link + m.imageUrl,
|
||||
iconUrl: combineUrl(proxyURL, m.link, m.iconUrl),
|
||||
imageUrl: combineUrl(proxyURL, m.link, m.imageUrl),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
import config from "../package.json";
|
||||
const { api, proxy } = config;
|
||||
|
||||
export const LANGUAGE = "language";
|
||||
export const ARTICLE_PINNED_KEY = "asc_article_pinned_key";
|
||||
|
||||
@ -135,3 +138,9 @@ export const LoaderStyle = {
|
||||
speed: 2,
|
||||
animate: true,
|
||||
};
|
||||
|
||||
export const AppServerConfig = {
|
||||
proxyURL: (proxy && proxy.url) || "",
|
||||
apiPrefixURL: (api && api.url) || "/api/2.0",
|
||||
apiTimeout: (api && api.timeout) || 30000,
|
||||
};
|
||||
|
@ -9,7 +9,10 @@
|
||||
"clean": "echo 'skip it'"
|
||||
},
|
||||
"api": {
|
||||
"url": "api/2.0",
|
||||
"url": "/api/2.0",
|
||||
"timeout": "30000"
|
||||
},
|
||||
"proxy": {
|
||||
"url": ""
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,10 @@ import ModuleStore from "./ModuleStore";
|
||||
import SettingsStore from "./SettingsStore";
|
||||
import UserStore from "./UserStore";
|
||||
import { logout as logoutDesktop, desktopConstants } from "../desktop";
|
||||
import { isAdmin } from "../utils";
|
||||
import { combineUrl, isAdmin } from "../utils";
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
import { AppServerConfig } from "../constants";
|
||||
const { proxyURL } = AppServerConfig;
|
||||
|
||||
class AuthStore {
|
||||
userStore = null;
|
||||
@ -81,32 +83,36 @@ class AuthStore {
|
||||
|
||||
get availableModules() {
|
||||
const { user } = this.userStore;
|
||||
const { modules, toModuleWrapper } = this.moduleStore;
|
||||
const { modules } = this.moduleStore;
|
||||
if (isEmpty(modules) || isEmpty(this.userStore.user)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const isUserAdmin = user.isAdmin;
|
||||
const customModules = this.getCustomModules(isUserAdmin);
|
||||
|
||||
const newModules = JSON.parse(JSON.stringify(modules));
|
||||
const products = newModules.map((m) => toModuleWrapper(m, false));
|
||||
const primaryProducts = products.filter((m) => m.isPrimary === true);
|
||||
const dummyProducts = products.filter((m) => m.isPrimary === false);
|
||||
const customProducts = this.getCustomModules(isUserAdmin);
|
||||
const readyProducts = [];
|
||||
const inProgressProducts = [];
|
||||
modules.forEach((p) => {
|
||||
if (p.appName === "people" || p.appName === "files") {
|
||||
readyProducts.push(p);
|
||||
} else {
|
||||
inProgressProducts.push(p);
|
||||
}
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
separator: true,
|
||||
id: "nav-products-separator",
|
||||
},
|
||||
...primaryProducts,
|
||||
...customModules,
|
||||
...readyProducts,
|
||||
...customProducts,
|
||||
{
|
||||
separator: true,
|
||||
dashed: true,
|
||||
id: "nav-dummy-products-separator",
|
||||
},
|
||||
...dummyProducts,
|
||||
...inProgressProducts,
|
||||
];
|
||||
}
|
||||
|
||||
@ -114,16 +120,15 @@ class AuthStore {
|
||||
if (!isAdmin) {
|
||||
return [];
|
||||
}
|
||||
const settingsModuleWrapper = this.moduleStore.toModuleWrapper(
|
||||
{
|
||||
id: "settings",
|
||||
title: "Settings",
|
||||
link: "/settings",
|
||||
},
|
||||
false,
|
||||
"SettingsIcon",
|
||||
"/static/images/settings.react.svg"
|
||||
);
|
||||
const settingsModuleWrapper = this.moduleStore.toModuleWrapper({
|
||||
id: "settings",
|
||||
title: "Settings",
|
||||
link: "/settings",
|
||||
iconUrl: "/static/images/settings.react.svg",
|
||||
});
|
||||
|
||||
settingsModuleWrapper.onClick = this.onClick;
|
||||
settingsModuleWrapper.onBadgeClick = this.onBadgeClick;
|
||||
|
||||
return [settingsModuleWrapper];
|
||||
};
|
||||
@ -171,7 +176,7 @@ class AuthStore {
|
||||
this.init();
|
||||
|
||||
if (!withoutRedirect) {
|
||||
history.push("/login");
|
||||
history.push(combineUrl(proxyURL, "/login"));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
import api from "../api";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import { combineUrl } from "../utils";
|
||||
import { AppServerConfig } from "../constants";
|
||||
const { proxyURL } = AppServerConfig;
|
||||
|
||||
class ModuleStore {
|
||||
isLoading = false;
|
||||
@ -13,134 +16,34 @@ class ModuleStore {
|
||||
getModules = async () => {
|
||||
const list = await api.modules.getModulesList();
|
||||
|
||||
const extendedModules = [
|
||||
...list,
|
||||
{
|
||||
id: "2A923037-8B2D-487b-9A22-5AC0918ACF3F",
|
||||
title: "Mail",
|
||||
link: "/products/mail/",
|
||||
originUrl: "/addons/mail/",
|
||||
helpUrl: "https://helpcenter.onlyoffice.com/userguides/mail.aspx",
|
||||
description:
|
||||
"Mail is a tool that allows to work with email messages right on your portal. It provides a variety of the standard capabilities implemented in any other email client.",
|
||||
isPrimary: false,
|
||||
},
|
||||
{
|
||||
id: "32D24CB5-7ECE-4606-9C94-19216BA42086",
|
||||
title: "Calendar",
|
||||
link: "/products/calendar/",
|
||||
originUrl: "/addons/calendar/",
|
||||
helpUrl: "https://helpcenter.onlyoffice.com/userguides/calendar.aspx",
|
||||
description:
|
||||
"Calendar is a built-in scheduling tool that allows you to always keep track of important events and meetings",
|
||||
isPrimary: false,
|
||||
},
|
||||
{
|
||||
id: "BF88953E-3C43-4850-A3FB-B1E43AD53A3E",
|
||||
title: "Talk",
|
||||
link: "/products/talk/",
|
||||
originUrl: "/addons/talk/",
|
||||
helpUrl: "https://helpcenter.onlyoffice.com/userguides/talk.aspx",
|
||||
description:
|
||||
"Talk is an instant messenger that provides a real-time communication between the co-workers. It offers all the traditional features you expect from a messenger: history archiving, file transfer, multi-user chat support, search function, emoticons.",
|
||||
isPrimary: false,
|
||||
},
|
||||
].map((m) => this.toModuleWrapper(m));
|
||||
const extendedModules = list.map((m) => this.toModuleWrapper(m));
|
||||
|
||||
this.setModules(extendedModules);
|
||||
};
|
||||
|
||||
toModuleWrapper = (
|
||||
item,
|
||||
noAction = true,
|
||||
iconName = null,
|
||||
iconUrl = null
|
||||
) => {
|
||||
toModuleWrapper = (item) => {
|
||||
const id =
|
||||
item.id && typeof item.id === "string" ? item.id.toLowerCase() : null;
|
||||
|
||||
const link = item.link
|
||||
? combineUrl(proxyURL, item.link.toLowerCase())
|
||||
: null;
|
||||
const iconUrl = item.iconUrl
|
||||
? combineUrl(proxyURL, item.iconUrl.toLowerCase())
|
||||
: null;
|
||||
const imageUrl = item.imageUrl
|
||||
? combineUrl(proxyURL, item.imageUrl.toLowerCase())
|
||||
: null;
|
||||
|
||||
const result = {
|
||||
...item,
|
||||
id,
|
||||
appName: "none",
|
||||
title: item.title,
|
||||
link: item.link,
|
||||
originUrl: item.originUrl,
|
||||
helpUrl: item.helpUrl,
|
||||
link,
|
||||
notifications: 0,
|
||||
iconName: item.iconName || iconName || "/static/images/people.react.svg", //TODO: Change to URL
|
||||
iconUrl: item.iconUrl || iconUrl,
|
||||
imageUrl: item.imageUrl,
|
||||
isolateMode: item.isolateMode,
|
||||
isPrimary: item.isPrimary,
|
||||
iconUrl,
|
||||
imageUrl,
|
||||
};
|
||||
|
||||
switch (id) {
|
||||
case "6743007c-6f95-4d20-8c88-a8601ce5e76d":
|
||||
result.appName = "crm";
|
||||
result.ready = false;
|
||||
result.iconName = "CrmIcon";
|
||||
result.iconUrl = "/static/images/crm.react.svg";
|
||||
result.imageUrl = "/images/crm.svg";
|
||||
result.helpUrl =
|
||||
"https://helpcenter.onlyoffice.com/userguides/crm.aspx";
|
||||
break;
|
||||
case "1e044602-43b5-4d79-82f3-fd6208a11960":
|
||||
result.appName = "projects";
|
||||
result.ready = false;
|
||||
result.iconName = "ProjectsIcon";
|
||||
result.iconUrl = "/static/images/projects.react.svg";
|
||||
result.imageUrl = "/images/projects.svg";
|
||||
result.helpUrl =
|
||||
"https://helpcenter.onlyoffice.com/userguides/projects.aspx";
|
||||
break;
|
||||
case "2a923037-8b2d-487b-9a22-5ac0918acf3f":
|
||||
result.appName = "mail";
|
||||
result.ready = false;
|
||||
result.iconName = "MailIcon";
|
||||
result.iconUrl = "/static/images/mail.react.svg";
|
||||
result.imageUrl = "/images/mail.svg";
|
||||
break;
|
||||
case "32d24cb5-7ece-4606-9c94-19216ba42086":
|
||||
result.appName = "calendar";
|
||||
result.ready = false;
|
||||
result.iconName = "CalendarCheckedIcon";
|
||||
result.iconUrl = "/static/images/calendar.checked.react.svg";
|
||||
result.imageUrl = "/images/calendar.svg";
|
||||
break;
|
||||
case "bf88953e-3c43-4850-a3fb-b1e43ad53a3e":
|
||||
result.appName = "chat";
|
||||
result.ready = false;
|
||||
result.iconName = "ChatIcon";
|
||||
result.iconUrl = "/static/images/chat.react.svg";
|
||||
result.imageUrl = "/images/talk.svg";
|
||||
result.isolateMode = true;
|
||||
break;
|
||||
case "e67be73d-f9ae-4ce1-8fec-1880cb518cb4":
|
||||
result.appName = "files";
|
||||
result.ready = true;
|
||||
break;
|
||||
case "f4d98afd-d336-4332-8778-3c6945c81ea0":
|
||||
result.appName = "people";
|
||||
result.ready = true;
|
||||
break;
|
||||
default:
|
||||
result.appName = "none";
|
||||
result.ready = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!noAction) {
|
||||
result.onClick = (e) => {
|
||||
if (e) {
|
||||
window.open(item.link, "_self");
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
result.onBadgeClick = (e) => console.log(iconName + " Badge Clicked", e);
|
||||
} else {
|
||||
result.description = item.description;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { action, computed, makeObservable, observable } from "mobx";
|
||||
import api from "../api";
|
||||
import { ARTICLE_PINNED_KEY, LANGUAGE } from "../constants";
|
||||
import { combineUrl } from "../utils";
|
||||
import { AppServerConfig } from "../constants";
|
||||
const { proxyURL } = AppServerConfig;
|
||||
|
||||
class SettingsStore {
|
||||
isLoading = false;
|
||||
@ -15,8 +18,8 @@ class SettingsStore {
|
||||
timezones = [];
|
||||
utcOffset = "00:00:00";
|
||||
utcHoursOffset = 0;
|
||||
defaultPage = "/"; //"/products/files";
|
||||
homepage = ""; //config.homepage;
|
||||
defaultPage = combineUrl(proxyURL, "/");
|
||||
homepage = "";
|
||||
datePattern = "M/d/yyyy";
|
||||
datePatternJQ = "00/00/0000";
|
||||
dateTimePattern = "dddd, MMMM d, yyyy h:mm:ss tt";
|
||||
@ -146,7 +149,12 @@ class SettingsStore {
|
||||
|
||||
Object.keys(newSettings).map((key) => {
|
||||
if (key in this) {
|
||||
this.setValue(key, newSettings[key]);
|
||||
this.setValue(
|
||||
key,
|
||||
key === "defaultPage"
|
||||
? combineUrl(proxyURL, newSettings[key])
|
||||
: newSettings[key]
|
||||
);
|
||||
|
||||
if (key === "culture" && !localStorage.getItem(LANGUAGE)) {
|
||||
localStorage.setItem(LANGUAGE, newSettings[key]);
|
||||
|
@ -150,3 +150,18 @@ export function isAdmin(currentUser, currentProductId) {
|
||||
|
||||
return currentUser.isAdmin || currentUser.isOwner || isProductAdmin;
|
||||
}
|
||||
|
||||
export function combineUrl(host = "", ...params) {
|
||||
let url = host.replace(/\/+$/, "");
|
||||
|
||||
params.forEach((part) => {
|
||||
const newPart = part.trim().replace(/^\/+/, "");
|
||||
url += newPart
|
||||
? url.length > 0 && url[url.length - 1] === "/"
|
||||
? newPart
|
||||
: `/${newPart}`
|
||||
: "";
|
||||
});
|
||||
|
||||
return url;
|
||||
}
|
||||
|
7
products/ASC.CRM/Client/.babelrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"presets": ["@babel/preset-react", "@babel/preset-env"],
|
||||
"plugins": [
|
||||
"@babel/plugin-transform-runtime",
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
]
|
||||
}
|
3
products/ASC.CRM/Client/.env
Normal file
@ -0,0 +1,3 @@
|
||||
PUBLIC_URL=/products/crm
|
||||
WDS_SOCKET_PATH=/products/crm/sockjs-node
|
||||
PORT=5014
|
21
products/ASC.CRM/Client/.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
15
products/ASC.CRM/Client/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
FROM node:12
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package.json ./
|
||||
COPY yarn.lock ./
|
||||
|
||||
RUN yarn install
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN yarn build
|
||||
|
||||
EXPOSE 5014
|
||||
|
||||
CMD [ "yarn", "build:start" ]
|
17
products/ASC.CRM/Client/analyse.js
Normal file
@ -0,0 +1,17 @@
|
||||
// script to enable webpack-bundle-analyzer
|
||||
process.env.NODE_ENV = "production";
|
||||
const webpack = require("webpack");
|
||||
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
|
||||
.BundleAnalyzerPlugin;
|
||||
const webpackConfigProd = require("react-scripts/config/webpack.config")(
|
||||
"production"
|
||||
);
|
||||
|
||||
webpackConfigProd.plugins.push(new BundleAnalyzerPlugin());
|
||||
|
||||
// actually running compilation and waiting for plugin to start explorer
|
||||
webpack(webpackConfigProd, (err, stats) => {
|
||||
if (err || stats.hasErrors()) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
84
products/ASC.CRM/Client/package.json
Normal file
@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "@appserver/crm",
|
||||
"version": "0.1.0",
|
||||
"private": "true",
|
||||
"homepage": "/products/crm",
|
||||
"title": "ONLYOFFICE",
|
||||
"id": "6743007c-6f95-4d20-8c88-a8601ce5e76d",
|
||||
"scripts": {
|
||||
"start": "webpack-cli serve",
|
||||
"start-prod": "webpack --mode production && serve dist -p 5014",
|
||||
"build": "webpack --mode production",
|
||||
"serve": "serve dist -p 5014",
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.12.1",
|
||||
"@babel/plugin-transform-runtime": "^7.12.1",
|
||||
"@babel/preset-env": "^7.12.7",
|
||||
"@babel/preset-react": "^7.12.10",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"compression-webpack-plugin": "^7.1.2",
|
||||
"copy-webpack-plugin": "^7.0.0",
|
||||
"css-loader": "^3.6.0",
|
||||
"html-webpack-plugin": "4.5.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"serve": "11.3.2",
|
||||
"source-map-loader": "^1.1.2",
|
||||
"style-loader": "1.2.1",
|
||||
"webpack": "5.14.0",
|
||||
"webpack-cli": "4.5.0",
|
||||
"webpack-dev-server": "3.11.2",
|
||||
"workbox-webpack-plugin": "^6.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"attr-accept": "^2.2.2",
|
||||
"axios": "^0.21.0",
|
||||
"email-addresses": "^3.1.0",
|
||||
"i18next": "^19.8.4",
|
||||
"i18next-http-backend": "^1.1.0",
|
||||
"mobx": "^6.1.1",
|
||||
"mobx-react": "^7.1.0",
|
||||
"moment": "^2.29.1",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"prop-types": "^15.7.2",
|
||||
"rc-tree": "^2.1.4",
|
||||
"re-resizable": "^6.9.0",
|
||||
"react": "^17.0.1",
|
||||
"react-autosize-textarea": "^7.1.0",
|
||||
"react-content-loader": "^5.1.4",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
"react-device-detect": "^1.14.0",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-dropzone": "^11.2.4",
|
||||
"react-i18next": "^11.7.3",
|
||||
"react-hammerjs": "^1.0.1",
|
||||
"react-onclickoutside": "^6.9.0",
|
||||
"react-player": "^1.15.3",
|
||||
"react-resize-detector": "^5.2.0",
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-string-format": "^0.1.0",
|
||||
"react-svg": "^12.0.0",
|
||||
"react-text-mask": "^5.4.3",
|
||||
"react-toastify": "^6.1.0",
|
||||
"react-tooltip": "^4.2.11",
|
||||
"react-viewer": "^3.2.2",
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.6",
|
||||
"react-window-infinite-loader": "^1.0.5",
|
||||
"resize-image": "^0.1.0",
|
||||
"sass": "^1.29.0",
|
||||
"sass-loader": "^10.1.0",
|
||||
"sjcl": "^1.0.8",
|
||||
"screenfull": "^5.1.0",
|
||||
"styled-components": "^5.2.1",
|
||||
"workbox-window": "^6.1.1"
|
||||
}
|
||||
}
|
BIN
products/ASC.CRM/Client/public/favicon.ico
Normal file
After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
261
products/ASC.CRM/Client/public/index.html
Normal file
@ -0,0 +1,261 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<!-- Tell the browser it's a PWA -->
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<!-- Tell iOS it's a PWA -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<link rel="apple-touch-icon" href="appIcon.png" />
|
||||
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i"
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
/>
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<style type="text/css">
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-size: 13px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.temp-header-container {
|
||||
align-items: center;
|
||||
background-color: rgb(15, 64, 113);
|
||||
display: grid;
|
||||
grid-template-columns: 24px 168px 1fr 36px;
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 16px;
|
||||
width: calc(100vw - 16px);
|
||||
height: 56px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
.temp-content-loader {
|
||||
padding: 16px;
|
||||
height: calc(100vh - 91px);
|
||||
display: grid;
|
||||
grid-template-columns: 250px 1fr;
|
||||
grid-template-rows: calc(100vh - 91px);
|
||||
grid-column-gap: 8px;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.temp-content-loader {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.temp-content__article {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.burger-loader-svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.logo-loader-svg {
|
||||
width: 168px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.avatar-loader-svg {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
</style>
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<div id="temp-content">
|
||||
<header class="temp-header-container">
|
||||
<div id="burger-loader-svg" class="burger-loader-svg">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria0"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
rx="3"
|
||||
ry="3"
|
||||
width="24"
|
||||
height="24"
|
||||
style="fill: url('#fill0');"
|
||||
></rect>
|
||||
<defs>
|
||||
<linearGradient id="fill0">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#fff"
|
||||
stop-opacity="0.25"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="logo-loader-svg" class="logo-loader-svg">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria01"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
rx="3"
|
||||
ry="3"
|
||||
width="168"
|
||||
height="24"
|
||||
style="fill: url('#fill01');"
|
||||
></rect>
|
||||
<defs>
|
||||
<linearGradient id="fill01">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#fff"
|
||||
stop-opacity="0.25"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div></div>
|
||||
<div id="avatar-loader-svg" class="avatar-loader-svg">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria01"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<circle
|
||||
cx="18"
|
||||
cy="18"
|
||||
r="18"
|
||||
width="36"
|
||||
height="36"
|
||||
style="fill: url('#fill02');"
|
||||
></circle>
|
||||
<defs>
|
||||
<linearGradient id="fill02">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#fff"
|
||||
stop-opacity="0.25"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="temp-content-loader">
|
||||
<div class="temp-content__article">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria1"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
clip-path="url(#clip-path1)"
|
||||
style="fill: url('#fill1');"
|
||||
></rect>
|
||||
<defs>
|
||||
<clipPath id="clip-path1">
|
||||
<rect x="3" y="3" rx="5" ry="5" width="100%" />
|
||||
</clipPath>
|
||||
<linearGradient id="fill1">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#000000"
|
||||
stop-opacity="0.1"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria2"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
clip-path="url(#clip-path2)"
|
||||
style="fill: url('#fill2');"
|
||||
></rect>
|
||||
<defs>
|
||||
<clipPath id="clip-path2">
|
||||
<rect x="3" y="3" rx="5" ry="5" width="100%" />
|
||||
</clipPath>
|
||||
<linearGradient id="fill2">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#000000"
|
||||
stop-opacity="0.1"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script>
|
||||
console.log("It's CRM INIT");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ComingSoon": "Coming soon",
|
||||
"ViewWeb": "View web version",
|
||||
"OpenApp": "Open your {{title}} app",
|
||||
"LearnMore": "Learn more"
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ComingSoon": "Скоро появится",
|
||||
"ViewWeb": "Просмотреть веб-версию",
|
||||
"OpenApp": "Откройте {{title}}",
|
||||
"LearnMore": "Узнать больше"
|
||||
}
|
15
products/ASC.CRM/Client/public/manifest.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"short_name": "ASC.People",
|
||||
"name": "ASC.People",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
7
products/ASC.CRM/Client/src/App.js
Normal file
@ -0,0 +1,7 @@
|
||||
//import "./wdyr";
|
||||
import React from "react";
|
||||
import Shell from "studio/shell";
|
||||
|
||||
const App = () => <Shell />;
|
||||
|
||||
export default App;
|
15
products/ASC.CRM/Client/src/App.test.js
Normal file
@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import App from "./App";
|
||||
|
||||
it("renders without crashing", async () => {
|
||||
const div = document.createElement("div");
|
||||
ReactDOM.render(
|
||||
<MemoryRouter>
|
||||
<App />
|
||||
</MemoryRouter>,
|
||||
div
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
});
|
67
products/ASC.CRM/Client/src/Crm.jsx
Normal file
@ -0,0 +1,67 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Provider as PeopleProvider, inject, observer } from "mobx-react";
|
||||
import { Switch } from "react-router-dom";
|
||||
import CrmStore from "./store/CrmStore";
|
||||
import ErrorBoundary from "@appserver/common/components/ErrorBoundary";
|
||||
import toastr from "studio/toastr";
|
||||
import PrivateRoute from "@appserver/common/components/PrivateRoute";
|
||||
import AppLoader from "@appserver/common/components/AppLoader";
|
||||
import { updateTempContent } from "@appserver/common/utils";
|
||||
import config from "../package.json";
|
||||
import "./custom.scss";
|
||||
import i18n from "./i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import Home from "./pages/Home";
|
||||
|
||||
const homepage = config.homepage;
|
||||
const Error404 = React.lazy(() => import("studio/Error404"));
|
||||
|
||||
const Error404Route = (props) => (
|
||||
<React.Suspense fallback={<AppLoader />}>
|
||||
<ErrorBoundary>
|
||||
<Error404 {...props} />
|
||||
</ErrorBoundary>
|
||||
</React.Suspense>
|
||||
);
|
||||
|
||||
const CrmContent = (props) => {
|
||||
const { isLoaded, loadBaseInfo } = props;
|
||||
|
||||
useEffect(() => {
|
||||
loadBaseInfo()
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => {
|
||||
//this.props.setIsLoaded(true);
|
||||
updateTempContent();
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoaded) updateTempContent();
|
||||
}, [isLoaded]);
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<PrivateRoute exact path={homepage} component={Home} />
|
||||
<PrivateRoute component={Error404Route} />
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
const Crm = inject(({ auth, crmStore }) => ({
|
||||
loadBaseInfo: async () => {
|
||||
await crmStore.init();
|
||||
auth.setProductVersion(config.version);
|
||||
},
|
||||
isLoaded: auth.isLoaded && crmStore.isLoaded,
|
||||
}))(observer(CrmContent));
|
||||
|
||||
const crmStore = new CrmStore();
|
||||
|
||||
export default (props) => (
|
||||
<PeopleProvider crmStore={crmStore}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<Crm {...props} />
|
||||
</I18nextProvider>
|
||||
</PeopleProvider>
|
||||
);
|
47
products/ASC.CRM/Client/src/bootstrap.js
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
import App from "./App";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import config from "../package.json";
|
||||
import { Workbox, messageSW } from "workbox-window";
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
|
||||
if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
|
||||
const wb = new Workbox(`${config.homepage}/sw.js`);
|
||||
|
||||
//TODO: watch https://developers.google.com/web/tools/workbox/guides/advanced-recipes and https://github.com/webmaxru/prog-web-news/blob/5ff94b45c9d317409c21c0fbb7d76e92f064471b/src/app/app-shell/app-shell.component.ts
|
||||
|
||||
// const showSkipWaitingPrompt = (event) => {
|
||||
// let snackBarRef = this.snackBar.open(
|
||||
// "A new version of the website available",
|
||||
// "Reload page",
|
||||
// {
|
||||
// duration: 5000,
|
||||
// }
|
||||
// );
|
||||
|
||||
// // Displaying prompt
|
||||
|
||||
// snackBarRef.onAction().subscribe(() => {
|
||||
// // Assuming the user accepted the update, set up a listener
|
||||
// // that will reload the page as soon as the previously waiting
|
||||
// // service worker has taken control.
|
||||
// wb.addEventListener("controlling", () => {
|
||||
// window.location.reload();
|
||||
// });
|
||||
|
||||
// // This will postMessage() to the waiting service worker.
|
||||
// wb.messageSkipWaiting();
|
||||
// });
|
||||
// };
|
||||
|
||||
// // Add an event listener to detect when the registered
|
||||
// // service worker has installed but is waiting to activate.
|
||||
// wb.addEventListener("waiting", showSkipWaitingPrompt);
|
||||
|
||||
wb.register()
|
||||
.then((reg) => {
|
||||
console.log("Successful service worker registration", reg);
|
||||
})
|
||||
.catch((err) => console.error("Service worker registration failed", err));
|
||||
}
|
27
products/ASC.CRM/Client/src/custom.scss
Normal file
@ -0,0 +1,27 @@
|
||||
// Override default variables before the import
|
||||
$font-family-base: "Open Sans", sans-serif;
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
min-height: 100%;
|
||||
position: relative;
|
||||
|
||||
.pageLoader {
|
||||
position: absolute;
|
||||
left: calc(50% - 20px);
|
||||
top: 35%;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.loading * {
|
||||
cursor: wait !important;
|
||||
}
|
26
products/ASC.CRM/Client/src/helpers/utils.js
Normal file
@ -0,0 +1,26 @@
|
||||
import authStore from "@appserver/common/store/AuthStore";
|
||||
//import store from "../store/store";
|
||||
|
||||
//const { getCurrentProduct } = commonStore.auth.selectors;
|
||||
|
||||
export const setDocumentTitle = (subTitle = null) => {
|
||||
// const state = store.getState();
|
||||
// const { auth: commonState } = state;
|
||||
const { isAuthenticated, settingsStore, product: currentModule } = authStore;
|
||||
const { organizationName } = settingsStore;
|
||||
|
||||
let title;
|
||||
if (subTitle) {
|
||||
if (isAuthenticated && currentModule) {
|
||||
title = subTitle + " - " + currentModule.title;
|
||||
} else {
|
||||
title = subTitle + " - " + organizationName;
|
||||
}
|
||||
} else if (currentModule && organizationName) {
|
||||
title = currentModule.title + " - " + organizationName;
|
||||
} else {
|
||||
title = organizationName;
|
||||
}
|
||||
|
||||
document.title = title;
|
||||
};
|
58
products/ASC.CRM/Client/src/i18n.js
Normal file
@ -0,0 +1,58 @@
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import config from "../package.json";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
|
||||
//import LanguageDetector from "i18next-browser-languagedetector";
|
||||
// not like to use this?
|
||||
// have a look at the Quick start guide
|
||||
// for passing in lng and translations on init
|
||||
|
||||
const languages = ["en", "ru"];
|
||||
|
||||
i18n
|
||||
/*
|
||||
load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
|
||||
learn more: https://github.com/i18next/i18next-http-backend
|
||||
*/
|
||||
.use(Backend)
|
||||
/*
|
||||
detect user language
|
||||
learn more: https://github.com/i18next/i18next-browser-languageDetector
|
||||
*/
|
||||
//.use(LanguageDetector)
|
||||
/*
|
||||
pass the i18n instance to react-i18next.
|
||||
*/
|
||||
.use(initReactI18next)
|
||||
/*
|
||||
init i18next
|
||||
for all options read: https://www.i18next.com/overview/configuration-options
|
||||
*/
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || "en",
|
||||
supportedLngs: languages,
|
||||
whitelist: languages,
|
||||
fallbackLng: "en",
|
||||
load: "languageOnly",
|
||||
//debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/{{lng}}/{{ns}}.json`,
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
1
products/ASC.CRM/Client/src/index.js
Normal file
@ -0,0 +1 @@
|
||||
import("./bootstrap");
|
243
products/ASC.CRM/Client/src/pages/Home/index.js
Normal file
@ -0,0 +1,243 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import PropTypes from "prop-types";
|
||||
import { withRouter } from "react-router";
|
||||
import Text from "@appserver/components/text";
|
||||
import Link from "@appserver/components/link";
|
||||
import Badge from "@appserver/components/badge";
|
||||
import Box from "@appserver/components/box";
|
||||
import EmptyScreenContainer from "@appserver/components/empty-screen-container";
|
||||
import ExternalLinkIcon from "../../../../../../public/images/external.link.react.svg";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import toastr from "studio/toastr";
|
||||
import PageLayout from "@appserver/common/components/PageLayout";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { isMobile, isIOS } from "react-device-detect";
|
||||
|
||||
import { setDocumentTitle } from "../../helpers/utils";
|
||||
import { inject } from "mobx-react";
|
||||
import i18n from "../../i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
|
||||
const commonStyles = `
|
||||
.link-box {
|
||||
margin: 8px 0;
|
||||
.view-web-link {
|
||||
margin: 8px;
|
||||
:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ComingSoonPage = styled.div`
|
||||
padding: ${isMobile ? "62px 0 0 0" : "0"};
|
||||
width: 336px;
|
||||
margin: 0 auto;
|
||||
|
||||
.module-logo-icon {
|
||||
float: left;
|
||||
margin-top: 8px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.module-title {
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.module-info {
|
||||
margin-bottom: 18px;
|
||||
.learn-more-link {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.coming-soon-badge {
|
||||
margin-bottom: 26px;
|
||||
}
|
||||
|
||||
${commonStyles}
|
||||
`;
|
||||
|
||||
const StyledDesktopContainer = styled(EmptyScreenContainer)`
|
||||
img {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
span:first-of-type {
|
||||
font-size: 24px;
|
||||
}
|
||||
span {
|
||||
font-size: 14px;
|
||||
> p {
|
||||
font-size: 14px;
|
||||
.learn-more-link {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
${commonStyles}
|
||||
|
||||
.view-web-link {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.coming-soon-badge > div > p {
|
||||
font-size: 13px;
|
||||
}
|
||||
`;
|
||||
|
||||
const ExternalLink = ({ label, href }) => (
|
||||
<Box className="link-box">
|
||||
<ExternalLinkIcon color="#333333" size={isMobile ? "small" : "medium"} />
|
||||
<Link
|
||||
as="a"
|
||||
href={href}
|
||||
target="_blank"
|
||||
className="view-web-link"
|
||||
color="#555F65"
|
||||
isBold
|
||||
isHovered
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const Body = ({ modules, match, isLoaded, setCurrentProductId }) => {
|
||||
const { t } = useTranslation("ComingSoon");
|
||||
const { error } = match.params;
|
||||
const { pathname, protocol, hostname } = window.location;
|
||||
const currentModule = modules.find((m) => m.link === pathname);
|
||||
const {
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
imageUrl,
|
||||
link,
|
||||
originUrl,
|
||||
helpUrl,
|
||||
} = currentModule;
|
||||
const url = originUrl ? originUrl : link;
|
||||
const webLink = protocol + "//" + hostname + url;
|
||||
const appLink = isIOS
|
||||
? id === "2A923037-8B2D-487b-9A22-5AC0918ACF3F"
|
||||
? "message:"
|
||||
: id === "32D24CB5-7ECE-4606-9C94-19216BA42086"
|
||||
? "calshow:"
|
||||
: false
|
||||
: false;
|
||||
|
||||
setDocumentTitle();
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentProductId(id);
|
||||
}, [id, setCurrentProductId]);
|
||||
|
||||
useEffect(() => error && toastr.error(error), [error]);
|
||||
|
||||
const appButtons = (
|
||||
<>
|
||||
<Badge
|
||||
label={t("ComingSoon")}
|
||||
maxWidth="150px"
|
||||
borderRadius="2px"
|
||||
className="coming-soon-badge"
|
||||
/>
|
||||
<ExternalLink label={t("ViewWeb")} href={webLink} />
|
||||
{appLink && (
|
||||
<ExternalLink
|
||||
label={t("OpenApp", {
|
||||
title: title,
|
||||
})}
|
||||
href={appLink}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const moduleDescription = (
|
||||
<Text className="module-info">
|
||||
{description}{" "}
|
||||
{helpUrl && (
|
||||
<Link
|
||||
as="a"
|
||||
href={helpUrl}
|
||||
target="_blank"
|
||||
className="learn-more-link"
|
||||
color="#555F65"
|
||||
isBold
|
||||
isHovered
|
||||
>
|
||||
{t("LearnMore")}...
|
||||
</Link>
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
return !isLoaded ? (
|
||||
<></>
|
||||
) : isMobile ? (
|
||||
<ComingSoonPage>
|
||||
<ReactSVG
|
||||
className="module-logo-icon"
|
||||
loading={() => (
|
||||
<Loaders.Rectangle
|
||||
width="100"
|
||||
height="14"
|
||||
backgroundColor="#fff"
|
||||
foregroundColor="#fff"
|
||||
backgroundOpacity={0.25}
|
||||
foregroundOpacity={0.2}
|
||||
/>
|
||||
)}
|
||||
src={imageUrl}
|
||||
/>
|
||||
<Box displayProp="flex" flexDirection="column" widthProp="220px">
|
||||
<Text fontWeight="600" fontSize="19px" className="module-title">
|
||||
{title}
|
||||
</Text>
|
||||
{moduleDescription}
|
||||
{appButtons}
|
||||
</Box>
|
||||
</ComingSoonPage>
|
||||
) : (
|
||||
<StyledDesktopContainer
|
||||
imageSrc={imageUrl}
|
||||
imageAlt={title}
|
||||
headerText={title}
|
||||
descriptionText={moduleDescription}
|
||||
buttons={appButtons}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ComingSoon = (props) => {
|
||||
return (
|
||||
<PageLayout>
|
||||
<PageLayout.SectionBody>
|
||||
<Body {...props} />
|
||||
</PageLayout.SectionBody>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
ComingSoon.propTypes = {
|
||||
modules: PropTypes.array,
|
||||
isLoaded: PropTypes.bool,
|
||||
};
|
||||
|
||||
const ComingSoonWrapper = inject(({ auth }) => ({
|
||||
modules: auth.moduleStore.modules,
|
||||
isLoaded: auth.isLoaded,
|
||||
setCurrentProductId: auth.settingsStore.setCurrentProductId,
|
||||
}))(withRouter(ComingSoon));
|
||||
|
||||
export default (props) => (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ComingSoonWrapper {...props} />
|
||||
</I18nextProvider>
|
||||
);
|
39
products/ASC.CRM/Client/src/store/CrmStore.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
import config from "../../package.json";
|
||||
import store from "studio/store";
|
||||
const { auth: authStore } = store;
|
||||
|
||||
class CrmStore {
|
||||
isLoading = false;
|
||||
isLoaded = false;
|
||||
isInit = false;
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
isLoading: observable,
|
||||
isLoaded: observable,
|
||||
setIsLoading: action,
|
||||
setIsLoaded: action,
|
||||
init: action,
|
||||
});
|
||||
}
|
||||
|
||||
init = async () => {
|
||||
if (this.isInit) return;
|
||||
this.isInit = true;
|
||||
|
||||
authStore.settingsStore.setModuleInfo(config.homepage, config.id);
|
||||
|
||||
this.setIsLoaded(true);
|
||||
};
|
||||
|
||||
setIsLoading = (loading) => {
|
||||
this.isLoading = loading;
|
||||
};
|
||||
|
||||
setIsLoaded = (isLoaded) => {
|
||||
this.isLoaded = isLoaded;
|
||||
};
|
||||
}
|
||||
|
||||
export default CrmStore;
|
116
products/ASC.CRM/Client/src/sw-template.js
Normal file
@ -0,0 +1,116 @@
|
||||
import {
|
||||
precacheAndRoute,
|
||||
cleanupOutdatedCaches,
|
||||
//createHandlerBoundToURL,
|
||||
} from "workbox-precaching";
|
||||
import { setCacheNameDetails } from "workbox-core";
|
||||
import { clientsClaim } from "workbox-core";
|
||||
import { /*NavigationRoute,*/ registerRoute } from "workbox-routing";
|
||||
import { googleFontsCache, imageCache, offlineFallback } from "workbox-recipes";
|
||||
import {
|
||||
//CacheFirst,
|
||||
//NetworkFirst,
|
||||
StaleWhileRevalidate,
|
||||
} from "workbox-strategies";
|
||||
import { ExpirationPlugin } from "workbox-expiration";
|
||||
//import { BroadcastUpdatePlugin } from "workbox-broadcast-update";
|
||||
|
||||
// SETTINGS
|
||||
|
||||
// Claiming control to start runtime caching asap
|
||||
clientsClaim();
|
||||
|
||||
// Use to update the app after user triggered refresh (without prompt)
|
||||
//self.skipWaiting();
|
||||
|
||||
// PRECACHING
|
||||
|
||||
// Setting custom cache name
|
||||
setCacheNameDetails({ precache: "wb6-precache", runtime: "wb6-runtime" });
|
||||
|
||||
// We inject manifest here using "workbox-build" in workbox-inject.js
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
|
||||
// Remove cache from the previous WB versions
|
||||
cleanupOutdatedCaches();
|
||||
|
||||
// NAVIGATION ROUTING
|
||||
|
||||
// This assumes /index.html has been precached.
|
||||
// const navHandler = createHandlerBoundToURL("/index.html");
|
||||
// const navigationRoute = new NavigationRoute(navHandler, {
|
||||
// denylist: [new RegExp("/out-of-spa/")], // Also might be specified explicitly via allowlist
|
||||
// });
|
||||
// registerRoute(navigationRoute);
|
||||
|
||||
// STATIC RESOURCES
|
||||
|
||||
googleFontsCache({ cachePrefix: "wb6-gfonts" });
|
||||
|
||||
// API ROUTING
|
||||
|
||||
registerRoute(
|
||||
// Cache API Request
|
||||
new RegExp("/api/2.0/(modules|people/@self|(.*)/info(.json|$))"),
|
||||
new StaleWhileRevalidate({
|
||||
cacheName: "wb6-api",
|
||||
plugins: [
|
||||
new ExpirationPlugin({
|
||||
maxEntries: 100,
|
||||
maxAgeSeconds: 30 * 60, // 30 Minutes
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
// TRANSLATIONS
|
||||
|
||||
registerRoute(
|
||||
({ url }) => url.pathname.indexOf("/locales/") !== -1,
|
||||
// Use cache but update in the background.
|
||||
new StaleWhileRevalidate({
|
||||
// Use a custom cache name.
|
||||
cacheName: "wb6-content-translation",
|
||||
})
|
||||
);
|
||||
|
||||
// CONTENT
|
||||
|
||||
imageCache({ cacheName: "wb6-content-images", maxEntries: 60 });
|
||||
|
||||
// APP SHELL UPDATE FLOW
|
||||
|
||||
addEventListener("message", (event) => {
|
||||
if (event.data && event.data.type === "SKIP_WAITING") {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
// FALLBACK
|
||||
|
||||
offlineFallback({
|
||||
pageFallback: "/static/offline/offline.html",
|
||||
imageFallback: "/static/offline/offline.svg",
|
||||
fontFallback: false,
|
||||
});
|
||||
|
||||
// ALL OTHER EVENTS
|
||||
|
||||
// Receive push and show a notification
|
||||
self.addEventListener("push", function (event) {
|
||||
console.log("[Service Worker]: Received push event", event);
|
||||
|
||||
var notificationData = {};
|
||||
|
||||
if (event.data.json()) {
|
||||
notificationData = event.data.json();
|
||||
} else {
|
||||
notificationData = {
|
||||
title: "Something Has Happened",
|
||||
message: "Something you might want to check out",
|
||||
icon: "/assets/img/pwa-logo.png",
|
||||
};
|
||||
}
|
||||
|
||||
self.registration.showNotification(notificationData.title, notificationData);
|
||||
});
|
12
products/ASC.CRM/Client/src/wdyr.js
Normal file
@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const whyDidYouRender = require("@welldone-software/why-did-you-render");
|
||||
whyDidYouRender(React, {
|
||||
trackAllPureComponents: true,
|
||||
collapseGroups: true,
|
||||
//trackExtraHooks: [
|
||||
// [ReactRedux, 'useSelector']
|
||||
//]
|
||||
});
|
||||
}
|
204
products/ASC.CRM/Client/webpack.config.js
Normal file
@ -0,0 +1,204 @@
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const ModuleFederationPlugin = require("webpack").container
|
||||
.ModuleFederationPlugin;
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const { InjectManifest } = require("workbox-webpack-plugin");
|
||||
//const CompressionPlugin = require("compression-webpack-plugin");
|
||||
|
||||
const path = require("path");
|
||||
const pkg = require("./package.json");
|
||||
const deps = pkg.dependencies;
|
||||
const homepage = pkg.homepage;
|
||||
const title = pkg.title;
|
||||
|
||||
var config = {
|
||||
mode: "development",
|
||||
entry: "./src/index",
|
||||
|
||||
devServer: {
|
||||
publicPath: homepage,
|
||||
|
||||
contentBase: [path.join(__dirname, "dist")],
|
||||
contentBasePublicPath: homepage,
|
||||
port: 5014,
|
||||
historyApiFallback: {
|
||||
// Paths with dots should still use the history fallback.
|
||||
// See https://github.com/facebook/create-react-app/issues/387.
|
||||
disableDotRule: true,
|
||||
index: homepage,
|
||||
},
|
||||
// proxy: [
|
||||
// {
|
||||
// context: "/api",
|
||||
// target: "http://localhost:8092",
|
||||
// },
|
||||
// ],
|
||||
hot: false,
|
||||
hotOnly: false,
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
||||
"Access-Control-Allow-Headers":
|
||||
"X-Requested-With, content-type, Authorization",
|
||||
},
|
||||
},
|
||||
|
||||
output: {
|
||||
publicPath: "auto",
|
||||
chunkFilename: "static/js/[id].[contenthash].js",
|
||||
//assetModuleFilename: "static/images/[hash][ext][query]",
|
||||
path: path.resolve(process.cwd(), "dist"),
|
||||
filename: "static/js/[name].[contenthash].bundle.js",
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: [".jsx", ".js", ".json"],
|
||||
fallback: {
|
||||
crypto: false,
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|ico)$/i,
|
||||
type: "asset/resource",
|
||||
generator: {
|
||||
filename: "static/images/[hash][ext][query]",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.m?js/,
|
||||
type: "javascript/auto",
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.react.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: "@svgr/webpack",
|
||||
options: {
|
||||
svgoConfig: {
|
||||
plugins: [{ removeViewBox: false }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ test: /\.json$/, loader: "json-loader" },
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
{
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: [
|
||||
// Creates `style` nodes from JS strings
|
||||
"style-loader",
|
||||
// Translates CSS into CommonJS
|
||||
"css-loader",
|
||||
// Compiles Sass to CSS
|
||||
"sass-loader",
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: ["@babel/preset-react", "@babel/preset-env"],
|
||||
plugins: [
|
||||
"@babel/plugin-transform-runtime",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-export-default-from",
|
||||
],
|
||||
},
|
||||
},
|
||||
"source-map-loader",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new ModuleFederationPlugin({
|
||||
name: "crm",
|
||||
filename: "remoteEntry.js",
|
||||
remotes: {
|
||||
studio: "studio@/remoteEntry.js",
|
||||
},
|
||||
exposes: {
|
||||
"./app": "./src/Crm.jsx",
|
||||
},
|
||||
shared: {
|
||||
...deps,
|
||||
react: {
|
||||
singleton: true,
|
||||
requiredVersion: deps.react,
|
||||
},
|
||||
"react-dom": {
|
||||
singleton: true,
|
||||
requiredVersion: deps["react-dom"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "./public/index.html",
|
||||
publicPath: homepage,
|
||||
title: title,
|
||||
base: `${homepage}/`,
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: "public",
|
||||
globOptions: {
|
||||
dot: true,
|
||||
gitignore: true,
|
||||
ignore: ["**/index.html"],
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
if (argv.mode === "production") {
|
||||
config.mode = "production";
|
||||
config.optimization = {
|
||||
splitChunks: { chunks: "all" },
|
||||
minimize: true,
|
||||
minimizer: [new TerserPlugin()],
|
||||
};
|
||||
config.plugins.push(
|
||||
new InjectManifest({
|
||||
mode: "production", //"development",
|
||||
swSrc: "./src/sw-template.js", // this is your sw template file
|
||||
swDest: "sw.js", // this will be created in the build step
|
||||
exclude: [/\.map$/, /manifest$/, /service-worker\.js$/],
|
||||
})
|
||||
);
|
||||
// config.plugins.push(
|
||||
// new CompressionPlugin({
|
||||
// filename: "[path][base].gz[query]",
|
||||
// algorithm: "gzip",
|
||||
// test: /\.js(\?.*)?$/i,
|
||||
// threshold: 10240,
|
||||
// minRatio: 0.8,
|
||||
// deleteOriginalAssets: true,
|
||||
// })
|
||||
// );
|
||||
} else {
|
||||
config.devtool = "cheap-module-source-map";
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
@ -95,8 +95,8 @@ namespace ASC.CRM.Configuration
|
||||
{
|
||||
//MasterPageFile = String.Concat(PathProvider.BaseVirtualPath, "Masters/BasicTemplate.Master"),
|
||||
DisabledIconFileName = "product_disabled_logo.png",
|
||||
IconFileName = "product_logo.png",
|
||||
LargeIconFileName = "product_logolarge.svg",
|
||||
IconFileName = "images/crm.menu.svg",
|
||||
LargeIconFileName = "images/crm.svg",
|
||||
DefaultSortOrder = 30,
|
||||
//SubscriptionManager = new ProductSubscriptionManager(),
|
||||
//SpaceUsageStatManager = new CRMSpaceUsageStatManager(),
|
||||
|
@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": "true",
|
||||
"homepage": "/products/files",
|
||||
"id": "e67be73d-f9ae-4ce1-8fec-1880cb518cb4",
|
||||
"title": "ONLYOFFICE",
|
||||
"scripts": {
|
||||
"start": "webpack-cli serve",
|
||||
|
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B |
@ -99,7 +99,7 @@ class InitFilesStore {
|
||||
setModuleInfo,
|
||||
} = auth.settingsStore;
|
||||
|
||||
setModuleInfo(config.homepage, "e67be73d-f9ae-4ce1-8fec-1880cb518cb4");
|
||||
setModuleInfo(config.homepage, config.id);
|
||||
|
||||
const requests = [];
|
||||
|
||||
|
@ -95,8 +95,8 @@ namespace ASC.Web.Files.Configuration
|
||||
_productContext =
|
||||
new ProductContext
|
||||
{
|
||||
DisabledIconFileName = "product_disabled_logo.png",
|
||||
IconFileName = "product_logo.png",
|
||||
DisabledIconFileName = "product_disabled_logo.png",
|
||||
IconFileName = "images/files.menu.svg",
|
||||
LargeIconFileName = "images/files.svg",
|
||||
DefaultSortOrder = 10,
|
||||
//SubscriptionManager = SubscriptionManager,
|
||||
@ -165,7 +165,7 @@ namespace ASC.Web.Files.Configuration
|
||||
|
||||
public override string ProductClassName
|
||||
{
|
||||
get { return "documents"; }
|
||||
get { return "files"; }
|
||||
}
|
||||
|
||||
public override ProductContext Context
|
||||
|
@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": "true",
|
||||
"homepage": "/products/people",
|
||||
"id": "f4d98afd-d336-4332-8778-3c6945c81ea0",
|
||||
"title": "ONLYOFFICE",
|
||||
"scripts": {
|
||||
"start": "webpack-cli serve",
|
||||
|
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 340 B |
@ -4,6 +4,7 @@ import {
|
||||
EmployeeStatus,
|
||||
} from "@appserver/common/constants";
|
||||
import { isAdmin } from "@appserver/common/utils";
|
||||
import { id } from "../../package.json";
|
||||
//const { isAdmin } = utils;
|
||||
|
||||
export const getUserStatus = (user) => {
|
||||
@ -26,7 +27,7 @@ export const getUserStatus = (user) => {
|
||||
|
||||
export const getUserRole = (user) => {
|
||||
if (user.isOwner) return "owner";
|
||||
else if (isAdmin(user, "f4d98afd-d336-4332-8778-3c6945c81ea0"))
|
||||
else if (isAdmin(user, id))
|
||||
//TODO: Change to People Product Id const
|
||||
return "admin";
|
||||
//TODO: Need refactoring
|
||||
|
@ -69,10 +69,7 @@ class PeopleStore {
|
||||
if (this.isInit) return;
|
||||
this.isInit = true;
|
||||
|
||||
authStore.settingsStore.setModuleInfo(
|
||||
config.homepage,
|
||||
"f4d98afd-d336-4332-8778-3c6945c81ea0"
|
||||
);
|
||||
authStore.settingsStore.setModuleInfo(config.homepage, config.id);
|
||||
|
||||
await this.groupsStore.getGroupList();
|
||||
await authStore.settingsStore.getPortalPasswordSettings();
|
||||
|
@ -67,14 +67,14 @@ namespace ASC.People
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsPrimary { get => true; }
|
||||
public override bool IsPrimary { get => false; }
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
_context = new ProductContext
|
||||
{
|
||||
DisabledIconFileName = "product_disabled_logo.png",
|
||||
IconFileName = "product_logo.png",
|
||||
IconFileName = "images/people.menu.svg",
|
||||
LargeIconFileName = "images/people.svg",
|
||||
DefaultSortOrder = 50,
|
||||
AdminOpportunities = () => PeopleResource.ProductAdminOpportunities.Split('|').ToList(),
|
||||
|
7
products/ASC.Projects/Client/.babelrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"presets": ["@babel/preset-react", "@babel/preset-env"],
|
||||
"plugins": [
|
||||
"@babel/plugin-transform-runtime",
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
]
|
||||
}
|
3
products/ASC.Projects/Client/.env
Normal file
@ -0,0 +1,3 @@
|
||||
PUBLIC_URL=/products/projects
|
||||
WDS_SOCKET_PATH=/products/projects/sockjs-node
|
||||
PORT=5015
|
21
products/ASC.Projects/Client/.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
15
products/ASC.Projects/Client/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
FROM node:12
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package.json ./
|
||||
COPY yarn.lock ./
|
||||
|
||||
RUN yarn install
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN yarn build
|
||||
|
||||
EXPOSE 5014
|
||||
|
||||
CMD [ "yarn", "build:start" ]
|
17
products/ASC.Projects/Client/analyse.js
Normal file
@ -0,0 +1,17 @@
|
||||
// script to enable webpack-bundle-analyzer
|
||||
process.env.NODE_ENV = "production";
|
||||
const webpack = require("webpack");
|
||||
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
|
||||
.BundleAnalyzerPlugin;
|
||||
const webpackConfigProd = require("react-scripts/config/webpack.config")(
|
||||
"production"
|
||||
);
|
||||
|
||||
webpackConfigProd.plugins.push(new BundleAnalyzerPlugin());
|
||||
|
||||
// actually running compilation and waiting for plugin to start explorer
|
||||
webpack(webpackConfigProd, (err, stats) => {
|
||||
if (err || stats.hasErrors()) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
84
products/ASC.Projects/Client/package.json
Normal file
@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "@appserver/projects",
|
||||
"version": "0.1.0",
|
||||
"private": "true",
|
||||
"homepage": "/products/projects",
|
||||
"id": "1e044602-43b5-4d79-82f3-fd6208a11960",
|
||||
"title": "ONLYOFFICE",
|
||||
"scripts": {
|
||||
"start": "webpack-cli serve",
|
||||
"start-prod": "webpack --mode production && serve dist -p 5015",
|
||||
"build": "webpack --mode production",
|
||||
"serve": "serve dist -p 5015",
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.12.1",
|
||||
"@babel/plugin-transform-runtime": "^7.12.1",
|
||||
"@babel/preset-env": "^7.12.7",
|
||||
"@babel/preset-react": "^7.12.10",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"compression-webpack-plugin": "^7.1.2",
|
||||
"copy-webpack-plugin": "^7.0.0",
|
||||
"css-loader": "^3.6.0",
|
||||
"html-webpack-plugin": "4.5.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"serve": "11.3.2",
|
||||
"source-map-loader": "^1.1.2",
|
||||
"style-loader": "1.2.1",
|
||||
"webpack": "5.14.0",
|
||||
"webpack-cli": "4.5.0",
|
||||
"webpack-dev-server": "3.11.2",
|
||||
"workbox-webpack-plugin": "^6.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"attr-accept": "^2.2.2",
|
||||
"axios": "^0.21.0",
|
||||
"email-addresses": "^3.1.0",
|
||||
"i18next": "^19.8.4",
|
||||
"i18next-http-backend": "^1.1.0",
|
||||
"mobx": "^6.1.1",
|
||||
"mobx-react": "^7.1.0",
|
||||
"moment": "^2.29.1",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"prop-types": "^15.7.2",
|
||||
"rc-tree": "^2.1.4",
|
||||
"re-resizable": "^6.9.0",
|
||||
"react": "^17.0.1",
|
||||
"react-autosize-textarea": "^7.1.0",
|
||||
"react-content-loader": "^5.1.4",
|
||||
"react-custom-scrollbars": "^4.2.1",
|
||||
"react-device-detect": "^1.14.0",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-dropzone": "^11.2.4",
|
||||
"react-i18next": "^11.7.3",
|
||||
"react-hammerjs": "^1.0.1",
|
||||
"react-onclickoutside": "^6.9.0",
|
||||
"react-player": "^1.15.3",
|
||||
"react-resize-detector": "^5.2.0",
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-string-format": "^0.1.0",
|
||||
"react-svg": "^12.0.0",
|
||||
"react-text-mask": "^5.4.3",
|
||||
"react-toastify": "^6.1.0",
|
||||
"react-tooltip": "^4.2.11",
|
||||
"react-viewer": "^3.2.2",
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.6",
|
||||
"react-window-infinite-loader": "^1.0.5",
|
||||
"resize-image": "^0.1.0",
|
||||
"sass": "^1.29.0",
|
||||
"sass-loader": "^10.1.0",
|
||||
"sjcl": "^1.0.8",
|
||||
"screenfull": "^5.1.0",
|
||||
"styled-components": "^5.2.1",
|
||||
"workbox-window": "^6.1.1"
|
||||
}
|
||||
}
|
BIN
products/ASC.Projects/Client/public/favicon.ico
Normal file
After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 902 B After Width: | Height: | Size: 902 B |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
261
products/ASC.Projects/Client/public/index.html
Normal file
@ -0,0 +1,261 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<!-- Tell the browser it's a PWA -->
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<!-- Tell iOS it's a PWA -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<link rel="apple-touch-icon" href="appIcon.png" />
|
||||
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i"
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
/>
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<style type="text/css">
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-size: 13px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.temp-header-container {
|
||||
align-items: center;
|
||||
background-color: rgb(15, 64, 113);
|
||||
display: grid;
|
||||
grid-template-columns: 24px 168px 1fr 36px;
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 16px;
|
||||
width: calc(100vw - 16px);
|
||||
height: 56px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
.temp-content-loader {
|
||||
padding: 16px;
|
||||
height: calc(100vh - 91px);
|
||||
display: grid;
|
||||
grid-template-columns: 250px 1fr;
|
||||
grid-template-rows: calc(100vh - 91px);
|
||||
grid-column-gap: 8px;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.temp-content-loader {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.temp-content__article {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.burger-loader-svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.logo-loader-svg {
|
||||
width: 168px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.avatar-loader-svg {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
</style>
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<div id="temp-content">
|
||||
<header class="temp-header-container">
|
||||
<div id="burger-loader-svg" class="burger-loader-svg">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria0"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
rx="3"
|
||||
ry="3"
|
||||
width="24"
|
||||
height="24"
|
||||
style="fill: url('#fill0');"
|
||||
></rect>
|
||||
<defs>
|
||||
<linearGradient id="fill0">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#fff"
|
||||
stop-opacity="0.25"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div id="logo-loader-svg" class="logo-loader-svg">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria01"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
rx="3"
|
||||
ry="3"
|
||||
width="168"
|
||||
height="24"
|
||||
style="fill: url('#fill01');"
|
||||
></rect>
|
||||
<defs>
|
||||
<linearGradient id="fill01">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#fff"
|
||||
stop-opacity="0.25"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div></div>
|
||||
<div id="avatar-loader-svg" class="avatar-loader-svg">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria01"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<circle
|
||||
cx="18"
|
||||
cy="18"
|
||||
r="18"
|
||||
width="36"
|
||||
height="36"
|
||||
style="fill: url('#fill02');"
|
||||
></circle>
|
||||
<defs>
|
||||
<linearGradient id="fill02">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#fff"
|
||||
stop-opacity="0.25"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="temp-content-loader">
|
||||
<div class="temp-content__article">
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria1"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
clip-path="url(#clip-path1)"
|
||||
style="fill: url('#fill1');"
|
||||
></rect>
|
||||
<defs>
|
||||
<clipPath id="clip-path1">
|
||||
<rect x="3" y="3" rx="5" ry="5" width="100%" />
|
||||
</clipPath>
|
||||
<linearGradient id="fill1">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#000000"
|
||||
stop-opacity="0.1"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<svg
|
||||
role="img"
|
||||
width="100%"
|
||||
height="100%"
|
||||
aria-labelledby="loading-aria2"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
clip-path="url(#clip-path2)"
|
||||
style="fill: url('#fill2');"
|
||||
></rect>
|
||||
<defs>
|
||||
<clipPath id="clip-path2">
|
||||
<rect x="3" y="3" rx="5" ry="5" width="100%" />
|
||||
</clipPath>
|
||||
<linearGradient id="fill2">
|
||||
<stop
|
||||
offset="0.599964"
|
||||
stop-color="#000000"
|
||||
stop-opacity="0.1"
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script>
|
||||
console.log("It's CRM INIT");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ComingSoon": "Coming soon",
|
||||
"ViewWeb": "View web version",
|
||||
"OpenApp": "Open your {{title}} app",
|
||||
"LearnMore": "Learn more"
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ComingSoon": "Скоро появится",
|
||||
"ViewWeb": "Просмотреть веб-версию",
|
||||
"OpenApp": "Откройте {{title}}",
|
||||
"LearnMore": "Узнать больше"
|
||||
}
|
15
products/ASC.Projects/Client/public/manifest.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"short_name": "ASC.People",
|
||||
"name": "ASC.People",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
7
products/ASC.Projects/Client/src/App.js
Normal file
@ -0,0 +1,7 @@
|
||||
//import "./wdyr";
|
||||
import React from "react";
|
||||
import Shell from "studio/shell";
|
||||
|
||||
const App = () => <Shell />;
|
||||
|
||||
export default App;
|
15
products/ASC.Projects/Client/src/App.test.js
Normal file
@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import App from "./App";
|
||||
|
||||
it("renders without crashing", async () => {
|
||||
const div = document.createElement("div");
|
||||
ReactDOM.render(
|
||||
<MemoryRouter>
|
||||
<App />
|
||||
</MemoryRouter>,
|
||||
div
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
});
|
67
products/ASC.Projects/Client/src/Projects.jsx
Normal file
@ -0,0 +1,67 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Provider as PeopleProvider, inject, observer } from "mobx-react";
|
||||
import { Switch } from "react-router-dom";
|
||||
import ProjectsStore from "./store/ProjectsStore";
|
||||
import ErrorBoundary from "@appserver/common/components/ErrorBoundary";
|
||||
import toastr from "studio/toastr";
|
||||
import PrivateRoute from "@appserver/common/components/PrivateRoute";
|
||||
import AppLoader from "@appserver/common/components/AppLoader";
|
||||
import { updateTempContent } from "@appserver/common/utils";
|
||||
import config from "../package.json";
|
||||
import "./custom.scss";
|
||||
import i18n from "./i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import Home from "./pages/Home";
|
||||
|
||||
const homepage = config.homepage;
|
||||
const Error404 = React.lazy(() => import("studio/Error404"));
|
||||
|
||||
const Error404Route = (props) => (
|
||||
<React.Suspense fallback={<AppLoader />}>
|
||||
<ErrorBoundary>
|
||||
<Error404 {...props} />
|
||||
</ErrorBoundary>
|
||||
</React.Suspense>
|
||||
);
|
||||
|
||||
const ProjectsContent = (props) => {
|
||||
const { isLoaded, loadBaseInfo } = props;
|
||||
|
||||
useEffect(() => {
|
||||
loadBaseInfo()
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => {
|
||||
//this.props.setIsLoaded(true);
|
||||
updateTempContent();
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoaded) updateTempContent();
|
||||
}, [isLoaded]);
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<PrivateRoute exact path={homepage} component={Home} />
|
||||
<PrivateRoute component={Error404Route} />
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
const Projects = inject(({ auth, projectsStore }) => ({
|
||||
loadBaseInfo: async () => {
|
||||
await projectsStore.init();
|
||||
auth.setProductVersion(config.version);
|
||||
},
|
||||
isLoaded: auth.isLoaded && projectsStore.isLoaded,
|
||||
}))(observer(ProjectsContent));
|
||||
|
||||
const projectsStore = new ProjectsStore();
|
||||
|
||||
export default (props) => (
|
||||
<PeopleProvider projectsStore={projectsStore}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<Projects {...props} />
|
||||
</I18nextProvider>
|
||||
</PeopleProvider>
|
||||
);
|
47
products/ASC.Projects/Client/src/bootstrap.js
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
import App from "./App";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import config from "../package.json";
|
||||
import { Workbox, messageSW } from "workbox-window";
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
|
||||
if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
|
||||
const wb = new Workbox(`${config.homepage}/sw.js`);
|
||||
|
||||
//TODO: watch https://developers.google.com/web/tools/workbox/guides/advanced-recipes and https://github.com/webmaxru/prog-web-news/blob/5ff94b45c9d317409c21c0fbb7d76e92f064471b/src/app/app-shell/app-shell.component.ts
|
||||
|
||||
// const showSkipWaitingPrompt = (event) => {
|
||||
// let snackBarRef = this.snackBar.open(
|
||||
// "A new version of the website available",
|
||||
// "Reload page",
|
||||
// {
|
||||
// duration: 5000,
|
||||
// }
|
||||
// );
|
||||
|
||||
// // Displaying prompt
|
||||
|
||||
// snackBarRef.onAction().subscribe(() => {
|
||||
// // Assuming the user accepted the update, set up a listener
|
||||
// // that will reload the page as soon as the previously waiting
|
||||
// // service worker has taken control.
|
||||
// wb.addEventListener("controlling", () => {
|
||||
// window.location.reload();
|
||||
// });
|
||||
|
||||
// // This will postMessage() to the waiting service worker.
|
||||
// wb.messageSkipWaiting();
|
||||
// });
|
||||
// };
|
||||
|
||||
// // Add an event listener to detect when the registered
|
||||
// // service worker has installed but is waiting to activate.
|
||||
// wb.addEventListener("waiting", showSkipWaitingPrompt);
|
||||
|
||||
wb.register()
|
||||
.then((reg) => {
|
||||
console.log("Successful service worker registration", reg);
|
||||
})
|
||||
.catch((err) => console.error("Service worker registration failed", err));
|
||||
}
|
27
products/ASC.Projects/Client/src/custom.scss
Normal file
@ -0,0 +1,27 @@
|
||||
// Override default variables before the import
|
||||
$font-family-base: "Open Sans", sans-serif;
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
min-height: 100%;
|
||||
position: relative;
|
||||
|
||||
.pageLoader {
|
||||
position: absolute;
|
||||
left: calc(50% - 20px);
|
||||
top: 35%;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.loading * {
|
||||
cursor: wait !important;
|
||||
}
|
26
products/ASC.Projects/Client/src/helpers/utils.js
Normal file
@ -0,0 +1,26 @@
|
||||
import authStore from "@appserver/common/store/AuthStore";
|
||||
//import store from "../store/store";
|
||||
|
||||
//const { getCurrentProduct } = commonStore.auth.selectors;
|
||||
|
||||
export const setDocumentTitle = (subTitle = null) => {
|
||||
// const state = store.getState();
|
||||
// const { auth: commonState } = state;
|
||||
const { isAuthenticated, settingsStore, product: currentModule } = authStore;
|
||||
const { organizationName } = settingsStore;
|
||||
|
||||
let title;
|
||||
if (subTitle) {
|
||||
if (isAuthenticated && currentModule) {
|
||||
title = subTitle + " - " + currentModule.title;
|
||||
} else {
|
||||
title = subTitle + " - " + organizationName;
|
||||
}
|
||||
} else if (currentModule && organizationName) {
|
||||
title = currentModule.title + " - " + organizationName;
|
||||
} else {
|
||||
title = organizationName;
|
||||
}
|
||||
|
||||
document.title = title;
|
||||
};
|
58
products/ASC.Projects/Client/src/i18n.js
Normal file
@ -0,0 +1,58 @@
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import config from "../package.json";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
|
||||
//import LanguageDetector from "i18next-browser-languagedetector";
|
||||
// not like to use this?
|
||||
// have a look at the Quick start guide
|
||||
// for passing in lng and translations on init
|
||||
|
||||
const languages = ["en", "ru"];
|
||||
|
||||
i18n
|
||||
/*
|
||||
load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
|
||||
learn more: https://github.com/i18next/i18next-http-backend
|
||||
*/
|
||||
.use(Backend)
|
||||
/*
|
||||
detect user language
|
||||
learn more: https://github.com/i18next/i18next-browser-languageDetector
|
||||
*/
|
||||
//.use(LanguageDetector)
|
||||
/*
|
||||
pass the i18n instance to react-i18next.
|
||||
*/
|
||||
.use(initReactI18next)
|
||||
/*
|
||||
init i18next
|
||||
for all options read: https://www.i18next.com/overview/configuration-options
|
||||
*/
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || "en",
|
||||
supportedLngs: languages,
|
||||
whitelist: languages,
|
||||
fallbackLng: "en",
|
||||
load: "languageOnly",
|
||||
//debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/{{lng}}/{{ns}}.json`,
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
1
products/ASC.Projects/Client/src/index.js
Normal file
@ -0,0 +1 @@
|
||||
import("./bootstrap");
|
243
products/ASC.Projects/Client/src/pages/Home/index.js
Normal file
@ -0,0 +1,243 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import PropTypes from "prop-types";
|
||||
import { withRouter } from "react-router";
|
||||
import Text from "@appserver/components/text";
|
||||
import Link from "@appserver/components/link";
|
||||
import Badge from "@appserver/components/badge";
|
||||
import Box from "@appserver/components/box";
|
||||
import EmptyScreenContainer from "@appserver/components/empty-screen-container";
|
||||
import ExternalLinkIcon from "../../../../../../public/images/external.link.react.svg";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import toastr from "studio/toastr";
|
||||
import PageLayout from "@appserver/common/components/PageLayout";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { isMobile, isIOS } from "react-device-detect";
|
||||
|
||||
import { setDocumentTitle } from "../../helpers/utils";
|
||||
import { inject } from "mobx-react";
|
||||
import i18n from "../../i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
|
||||
const commonStyles = `
|
||||
.link-box {
|
||||
margin: 8px 0;
|
||||
.view-web-link {
|
||||
margin: 8px;
|
||||
:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ComingSoonPage = styled.div`
|
||||
padding: ${isMobile ? "62px 0 0 0" : "0"};
|
||||
width: 336px;
|
||||
margin: 0 auto;
|
||||
|
||||
.module-logo-icon {
|
||||
float: left;
|
||||
margin-top: 8px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.module-title {
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.module-info {
|
||||
margin-bottom: 18px;
|
||||
.learn-more-link {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.coming-soon-badge {
|
||||
margin-bottom: 26px;
|
||||
}
|
||||
|
||||
${commonStyles}
|
||||
`;
|
||||
|
||||
const StyledDesktopContainer = styled(EmptyScreenContainer)`
|
||||
img {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
span:first-of-type {
|
||||
font-size: 24px;
|
||||
}
|
||||
span {
|
||||
font-size: 14px;
|
||||
> p {
|
||||
font-size: 14px;
|
||||
.learn-more-link {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
${commonStyles}
|
||||
|
||||
.view-web-link {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.coming-soon-badge > div > p {
|
||||
font-size: 13px;
|
||||
}
|
||||
`;
|
||||
|
||||
const ExternalLink = ({ label, href }) => (
|
||||
<Box className="link-box">
|
||||
<ExternalLinkIcon color="#333333" size={isMobile ? "small" : "medium"} />
|
||||
<Link
|
||||
as="a"
|
||||
href={href}
|
||||
target="_blank"
|
||||
className="view-web-link"
|
||||
color="#555F65"
|
||||
isBold
|
||||
isHovered
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const Body = ({ modules, match, isLoaded, setCurrentProductId }) => {
|
||||
const { t } = useTranslation("ComingSoon");
|
||||
const { error } = match.params;
|
||||
const { pathname, protocol, hostname } = window.location;
|
||||
const currentModule = modules.find((m) => m.link === pathname);
|
||||
const {
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
imageUrl,
|
||||
link,
|
||||
originUrl,
|
||||
helpUrl,
|
||||
} = currentModule;
|
||||
const url = originUrl ? originUrl : link;
|
||||
const webLink = protocol + "//" + hostname + url;
|
||||
const appLink = isIOS
|
||||
? id === "2A923037-8B2D-487b-9A22-5AC0918ACF3F"
|
||||
? "message:"
|
||||
: id === "32D24CB5-7ECE-4606-9C94-19216BA42086"
|
||||
? "calshow:"
|
||||
: false
|
||||
: false;
|
||||
|
||||
setDocumentTitle();
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentProductId(id);
|
||||
}, [id, setCurrentProductId]);
|
||||
|
||||
useEffect(() => error && toastr.error(error), [error]);
|
||||
|
||||
const appButtons = (
|
||||
<>
|
||||
<Badge
|
||||
label={t("ComingSoon")}
|
||||
maxWidth="150px"
|
||||
borderRadius="2px"
|
||||
className="coming-soon-badge"
|
||||
/>
|
||||
<ExternalLink label={t("ViewWeb")} href={webLink} />
|
||||
{appLink && (
|
||||
<ExternalLink
|
||||
label={t("OpenApp", {
|
||||
title: title,
|
||||
})}
|
||||
href={appLink}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const moduleDescription = (
|
||||
<Text className="module-info">
|
||||
{description}{" "}
|
||||
{helpUrl && (
|
||||
<Link
|
||||
as="a"
|
||||
href={helpUrl}
|
||||
target="_blank"
|
||||
className="learn-more-link"
|
||||
color="#555F65"
|
||||
isBold
|
||||
isHovered
|
||||
>
|
||||
{t("LearnMore")}...
|
||||
</Link>
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
return !isLoaded ? (
|
||||
<></>
|
||||
) : isMobile ? (
|
||||
<ComingSoonPage>
|
||||
<ReactSVG
|
||||
className="module-logo-icon"
|
||||
loading={() => (
|
||||
<Loaders.Rectangle
|
||||
width="100"
|
||||
height="14"
|
||||
backgroundColor="#fff"
|
||||
foregroundColor="#fff"
|
||||
backgroundOpacity={0.25}
|
||||
foregroundOpacity={0.2}
|
||||
/>
|
||||
)}
|
||||
src={imageUrl}
|
||||
/>
|
||||
<Box displayProp="flex" flexDirection="column" widthProp="220px">
|
||||
<Text fontWeight="600" fontSize="19px" className="module-title">
|
||||
{title}
|
||||
</Text>
|
||||
{moduleDescription}
|
||||
{appButtons}
|
||||
</Box>
|
||||
</ComingSoonPage>
|
||||
) : (
|
||||
<StyledDesktopContainer
|
||||
imageSrc={imageUrl}
|
||||
imageAlt={title}
|
||||
headerText={title}
|
||||
descriptionText={moduleDescription}
|
||||
buttons={appButtons}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ComingSoon = (props) => {
|
||||
return (
|
||||
<PageLayout>
|
||||
<PageLayout.SectionBody>
|
||||
<Body {...props} />
|
||||
</PageLayout.SectionBody>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
ComingSoon.propTypes = {
|
||||
modules: PropTypes.array,
|
||||
isLoaded: PropTypes.bool,
|
||||
};
|
||||
|
||||
const ComingSoonWrapper = inject(({ auth }) => ({
|
||||
modules: auth.moduleStore.modules,
|
||||
isLoaded: auth.isLoaded,
|
||||
setCurrentProductId: auth.settingsStore.setCurrentProductId,
|
||||
}))(withRouter(ComingSoon));
|
||||
|
||||
export default (props) => (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ComingSoonWrapper {...props} />
|
||||
</I18nextProvider>
|
||||
);
|
39
products/ASC.Projects/Client/src/store/ProjectsStore.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
import config from "../../package.json";
|
||||
import store from "studio/store";
|
||||
const { auth: authStore } = store;
|
||||
|
||||
class ProjectsStore {
|
||||
isLoading = false;
|
||||
isLoaded = false;
|
||||
isInit = false;
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
isLoading: observable,
|
||||
isLoaded: observable,
|
||||
setIsLoading: action,
|
||||
setIsLoaded: action,
|
||||
init: action,
|
||||
});
|
||||
}
|
||||
|
||||
init = async () => {
|
||||
if (this.isInit) return;
|
||||
this.isInit = true;
|
||||
|
||||
authStore.settingsStore.setModuleInfo(config.homepage, config.id);
|
||||
|
||||
this.setIsLoaded(true);
|
||||
};
|
||||
|
||||
setIsLoading = (loading) => {
|
||||
this.isLoading = loading;
|
||||
};
|
||||
|
||||
setIsLoaded = (isLoaded) => {
|
||||
this.isLoaded = isLoaded;
|
||||
};
|
||||
}
|
||||
|
||||
export default ProjectsStore;
|
116
products/ASC.Projects/Client/src/sw-template.js
Normal file
@ -0,0 +1,116 @@
|
||||
import {
|
||||
precacheAndRoute,
|
||||
cleanupOutdatedCaches,
|
||||
//createHandlerBoundToURL,
|
||||
} from "workbox-precaching";
|
||||
import { setCacheNameDetails } from "workbox-core";
|
||||
import { clientsClaim } from "workbox-core";
|
||||
import { /*NavigationRoute,*/ registerRoute } from "workbox-routing";
|
||||
import { googleFontsCache, imageCache, offlineFallback } from "workbox-recipes";
|
||||
import {
|
||||
//CacheFirst,
|
||||
//NetworkFirst,
|
||||
StaleWhileRevalidate,
|
||||
} from "workbox-strategies";
|
||||
import { ExpirationPlugin } from "workbox-expiration";
|
||||
//import { BroadcastUpdatePlugin } from "workbox-broadcast-update";
|
||||
|
||||
// SETTINGS
|
||||
|
||||
// Claiming control to start runtime caching asap
|
||||
clientsClaim();
|
||||
|
||||
// Use to update the app after user triggered refresh (without prompt)
|
||||
//self.skipWaiting();
|
||||
|
||||
// PRECACHING
|
||||
|
||||
// Setting custom cache name
|
||||
setCacheNameDetails({ precache: "wb6-precache", runtime: "wb6-runtime" });
|
||||
|
||||
// We inject manifest here using "workbox-build" in workbox-inject.js
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
|
||||
// Remove cache from the previous WB versions
|
||||
cleanupOutdatedCaches();
|
||||
|
||||
// NAVIGATION ROUTING
|
||||
|
||||
// This assumes /index.html has been precached.
|
||||
// const navHandler = createHandlerBoundToURL("/index.html");
|
||||
// const navigationRoute = new NavigationRoute(navHandler, {
|
||||
// denylist: [new RegExp("/out-of-spa/")], // Also might be specified explicitly via allowlist
|
||||
// });
|
||||
// registerRoute(navigationRoute);
|
||||
|
||||
// STATIC RESOURCES
|
||||
|
||||
googleFontsCache({ cachePrefix: "wb6-gfonts" });
|
||||
|
||||
// API ROUTING
|
||||
|
||||
registerRoute(
|
||||
// Cache API Request
|
||||
new RegExp("/api/2.0/(modules|people/@self|(.*)/info(.json|$))"),
|
||||
new StaleWhileRevalidate({
|
||||
cacheName: "wb6-api",
|
||||
plugins: [
|
||||
new ExpirationPlugin({
|
||||
maxEntries: 100,
|
||||
maxAgeSeconds: 30 * 60, // 30 Minutes
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
// TRANSLATIONS
|
||||
|
||||
registerRoute(
|
||||
({ url }) => url.pathname.indexOf("/locales/") !== -1,
|
||||
// Use cache but update in the background.
|
||||
new StaleWhileRevalidate({
|
||||
// Use a custom cache name.
|
||||
cacheName: "wb6-content-translation",
|
||||
})
|
||||
);
|
||||
|
||||
// CONTENT
|
||||
|
||||
imageCache({ cacheName: "wb6-content-images", maxEntries: 60 });
|
||||
|
||||
// APP SHELL UPDATE FLOW
|
||||
|
||||
addEventListener("message", (event) => {
|
||||
if (event.data && event.data.type === "SKIP_WAITING") {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
// FALLBACK
|
||||
|
||||
offlineFallback({
|
||||
pageFallback: "/static/offline/offline.html",
|
||||
imageFallback: "/static/offline/offline.svg",
|
||||
fontFallback: false,
|
||||
});
|
||||
|
||||
// ALL OTHER EVENTS
|
||||
|
||||
// Receive push and show a notification
|
||||
self.addEventListener("push", function (event) {
|
||||
console.log("[Service Worker]: Received push event", event);
|
||||
|
||||
var notificationData = {};
|
||||
|
||||
if (event.data.json()) {
|
||||
notificationData = event.data.json();
|
||||
} else {
|
||||
notificationData = {
|
||||
title: "Something Has Happened",
|
||||
message: "Something you might want to check out",
|
||||
icon: "/assets/img/pwa-logo.png",
|
||||
};
|
||||
}
|
||||
|
||||
self.registration.showNotification(notificationData.title, notificationData);
|
||||
});
|
12
products/ASC.Projects/Client/src/wdyr.js
Normal file
@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const whyDidYouRender = require("@welldone-software/why-did-you-render");
|
||||
whyDidYouRender(React, {
|
||||
trackAllPureComponents: true,
|
||||
collapseGroups: true,
|
||||
//trackExtraHooks: [
|
||||
// [ReactRedux, 'useSelector']
|
||||
//]
|
||||
});
|
||||
}
|
204
products/ASC.Projects/Client/webpack.config.js
Normal file
@ -0,0 +1,204 @@
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const ModuleFederationPlugin = require("webpack").container
|
||||
.ModuleFederationPlugin;
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const { InjectManifest } = require("workbox-webpack-plugin");
|
||||
//const CompressionPlugin = require("compression-webpack-plugin");
|
||||
|
||||
const path = require("path");
|
||||
const pkg = require("./package.json");
|
||||
const deps = pkg.dependencies;
|
||||
const homepage = pkg.homepage;
|
||||
const title = pkg.title;
|
||||
|
||||
var config = {
|
||||
mode: "development",
|
||||
entry: "./src/index",
|
||||
|
||||
devServer: {
|
||||
publicPath: homepage,
|
||||
|
||||
contentBase: [path.join(__dirname, "dist")],
|
||||
contentBasePublicPath: homepage,
|
||||
port: 5015,
|
||||
historyApiFallback: {
|
||||
// Paths with dots should still use the history fallback.
|
||||
// See https://github.com/facebook/create-react-app/issues/387.
|
||||
disableDotRule: true,
|
||||
index: homepage,
|
||||
},
|
||||
// proxy: [
|
||||
// {
|
||||
// context: "/api",
|
||||
// target: "http://localhost:8092",
|
||||
// },
|
||||
// ],
|
||||
hot: false,
|
||||
hotOnly: false,
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
||||
"Access-Control-Allow-Headers":
|
||||
"X-Requested-With, content-type, Authorization",
|
||||
},
|
||||
},
|
||||
|
||||
output: {
|
||||
publicPath: "auto",
|
||||
chunkFilename: "static/js/[id].[contenthash].js",
|
||||
//assetModuleFilename: "static/images/[hash][ext][query]",
|
||||
path: path.resolve(process.cwd(), "dist"),
|
||||
filename: "static/js/[name].[contenthash].bundle.js",
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: [".jsx", ".js", ".json"],
|
||||
fallback: {
|
||||
crypto: false,
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|ico)$/i,
|
||||
type: "asset/resource",
|
||||
generator: {
|
||||
filename: "static/images/[hash][ext][query]",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.m?js/,
|
||||
type: "javascript/auto",
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.react.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: "@svgr/webpack",
|
||||
options: {
|
||||
svgoConfig: {
|
||||
plugins: [{ removeViewBox: false }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ test: /\.json$/, loader: "json-loader" },
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
{
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: [
|
||||
// Creates `style` nodes from JS strings
|
||||
"style-loader",
|
||||
// Translates CSS into CommonJS
|
||||
"css-loader",
|
||||
// Compiles Sass to CSS
|
||||
"sass-loader",
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: ["@babel/preset-react", "@babel/preset-env"],
|
||||
plugins: [
|
||||
"@babel/plugin-transform-runtime",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-export-default-from",
|
||||
],
|
||||
},
|
||||
},
|
||||
"source-map-loader",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new ModuleFederationPlugin({
|
||||
name: "projects",
|
||||
filename: "remoteEntry.js",
|
||||
remotes: {
|
||||
studio: "studio@/remoteEntry.js",
|
||||
},
|
||||
exposes: {
|
||||
"./app": "./src/Projects.jsx",
|
||||
},
|
||||
shared: {
|
||||
...deps,
|
||||
react: {
|
||||
singleton: true,
|
||||
requiredVersion: deps.react,
|
||||
},
|
||||
"react-dom": {
|
||||
singleton: true,
|
||||
requiredVersion: deps["react-dom"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "./public/index.html",
|
||||
publicPath: homepage,
|
||||
title: title,
|
||||
base: `${homepage}/`,
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: "public",
|
||||
globOptions: {
|
||||
dot: true,
|
||||
gitignore: true,
|
||||
ignore: ["**/index.html"],
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
if (argv.mode === "production") {
|
||||
config.mode = "production";
|
||||
config.optimization = {
|
||||
splitChunks: { chunks: "all" },
|
||||
minimize: true,
|
||||
minimizer: [new TerserPlugin()],
|
||||
};
|
||||
config.plugins.push(
|
||||
new InjectManifest({
|
||||
mode: "production", //"development",
|
||||
swSrc: "./src/sw-template.js", // this is your sw template file
|
||||
swDest: "sw.js", // this will be created in the build step
|
||||
exclude: [/\.map$/, /manifest$/, /service-worker\.js$/],
|
||||
})
|
||||
);
|
||||
// config.plugins.push(
|
||||
// new CompressionPlugin({
|
||||
// filename: "[path][base].gz[query]",
|
||||
// algorithm: "gzip",
|
||||
// test: /\.js(\?.*)?$/i,
|
||||
// threshold: 10240,
|
||||
// minRatio: 0.8,
|
||||
// deleteOriginalAssets: true,
|
||||
// })
|
||||
// );
|
||||
} else {
|
||||
config.devtool = "cheap-module-source-map";
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
@ -122,8 +122,8 @@ namespace ASC.Projects.Configuration
|
||||
{
|
||||
//MasterPageFile = String.Concat(PathProvider.BaseVirtualPath, "Masters/BasicTemplate.Master"),
|
||||
DisabledIconFileName = "product_disabled_logo.png",
|
||||
IconFileName = "product_logo.png",
|
||||
LargeIconFileName = "product_logolarge.svg",
|
||||
IconFileName = "images/projects.menu.svg",
|
||||
LargeIconFileName = "images/projects.svg",
|
||||
//SubscriptionManager = new ProductSubscriptionManager(),
|
||||
DefaultSortOrder = 20,
|
||||
//SpaceUsageStatManager = new ProjectsSpaceUsageStatManager(),
|
||||
|
7
public/images/people.menu.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 16 16">
|
||||
<title>calendar</title>
|
||||
<g>
|
||||
<path d="M10 10v-1.5c0.459-0.185 0.815-0.541 0.996-0.988l0.004-0.012v-3c0-1-1-2.5-2-2.5h-2c-1 0-2 1.5-2 2.5v3c0.185 0.459 0.541 0.815 0.988 0.996l0.012 0.004v1.5s-4 2-4 3v1h12v-1c0-1-4-3-4-3z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 340 B |
@ -11,7 +11,7 @@ import Layout from "./components/Layout";
|
||||
import ScrollToTop from "./components/Layout/ScrollToTop";
|
||||
import history from "@appserver/common/history";
|
||||
import toastr from "studio/toastr";
|
||||
import { updateTempContent } from "@appserver/common/utils";
|
||||
import { combineUrl, updateTempContent } from "@appserver/common/utils";
|
||||
import { Provider as MobxProvider } from "mobx-react";
|
||||
import ThemeProvider from "@appserver/components/theme-provider";
|
||||
import { Base } from "@appserver/components/themes";
|
||||
@ -22,9 +22,57 @@ import { I18nextProvider } from "react-i18next";
|
||||
import i18n from "./i18n";
|
||||
import AppLoader from "@appserver/common/components/AppLoader";
|
||||
import System from "./components/System";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
||||
const { proxyURL } = AppServerConfig;
|
||||
const homepage = config.homepage;
|
||||
|
||||
const PROXY_HOMEPAGE_URL = combineUrl(proxyURL, homepage);
|
||||
const HOME_URLS = [
|
||||
combineUrl(PROXY_HOMEPAGE_URL, "/") || "/",
|
||||
combineUrl(PROXY_HOMEPAGE_URL, "/error=:error"),
|
||||
];
|
||||
const WIZARD_URL = combineUrl(PROXY_HOMEPAGE_URL, "/wizard");
|
||||
const ABOUT_URL = combineUrl(PROXY_HOMEPAGE_URL, "/about");
|
||||
const LOGIN_URLS = [
|
||||
combineUrl(PROXY_HOMEPAGE_URL, "/login"),
|
||||
combineUrl(PROXY_HOMEPAGE_URL, "/login/error=:error"),
|
||||
combineUrl(PROXY_HOMEPAGE_URL, "/login/confirmed-email=:confirmedEmail"),
|
||||
];
|
||||
const CONFIRM_URL = combineUrl(PROXY_HOMEPAGE_URL, "/confirm");
|
||||
const COMING_SOON_URLS = [
|
||||
combineUrl(PROXY_HOMEPAGE_URL, "/coming-soon"),
|
||||
//combineUrl(PROXY_HOMEPAGE_URL, "/products/mail"),
|
||||
//combineUrl(PROXY_HOMEPAGE_URL, "/products/projects"),
|
||||
//combineUrl(PROXY_HOMEPAGE_URL, "/products/crm"),
|
||||
//combineUrl(PROXY_HOMEPAGE_URL, "/products/calendar"),
|
||||
//combineUrl(PROXY_HOMEPAGE_URL, "/products/talk/"),
|
||||
];
|
||||
const THIRD_PARTY_RESPONSE_URL = combineUrl(
|
||||
PROXY_HOMEPAGE_URL,
|
||||
"/thirdparty/:provider"
|
||||
);
|
||||
const PAYMENTS_URL = combineUrl(PROXY_HOMEPAGE_URL, "/payments");
|
||||
const SETTINGS_URL = combineUrl(PROXY_HOMEPAGE_URL, "/settings");
|
||||
const ERROR_401_URL = combineUrl(PROXY_HOMEPAGE_URL, "/error401");
|
||||
|
||||
if (!window.AppServer) {
|
||||
window.AppServer = {};
|
||||
}
|
||||
|
||||
window.AppServer.studio = {
|
||||
HOME_URLS,
|
||||
WIZARD_URL,
|
||||
ABOUT_URL,
|
||||
LOGIN_URLS,
|
||||
CONFIRM_URL,
|
||||
COMING_SOON_URLS,
|
||||
THIRD_PARTY_RESPONSE_URL,
|
||||
PAYMENTS_URL,
|
||||
SETTINGS_URL,
|
||||
ERROR_401_URL,
|
||||
};
|
||||
|
||||
const Payments = React.lazy(() => import("./components/pages/Payments"));
|
||||
const Error404 = React.lazy(() => import("studio/Error404"));
|
||||
const Error401 = React.lazy(() => import("studio/Error401"));
|
||||
@ -126,40 +174,6 @@ const ThirdPartyResponseRoute = (props) => (
|
||||
);
|
||||
|
||||
const Shell = ({ items = [], page = "home", ...rest }) => {
|
||||
// useEffect(() => {
|
||||
// //utils.removeTempContent();
|
||||
|
||||
// const {
|
||||
// getPortalSettings,
|
||||
// getUser,
|
||||
// getModules,
|
||||
// setIsLoaded,
|
||||
// getIsAuthenticated,
|
||||
// } = rest;
|
||||
|
||||
// getIsAuthenticated()
|
||||
// .then((isAuthenticated) => {
|
||||
// if (isAuthenticated) updateTempContent(isAuthenticated);
|
||||
|
||||
// const requests = [];
|
||||
// if (!isAuthenticated) {
|
||||
// requests.push(getPortalSettings());
|
||||
// } else if (
|
||||
// !window.location.pathname.includes("confirm/EmailActivation")
|
||||
// ) {
|
||||
// requests.push(getUser());
|
||||
// requests.push(getPortalSettings());
|
||||
// requests.push(getModules());
|
||||
// }
|
||||
|
||||
// return Promise.all(requests).finally(() => {
|
||||
// updateTempContent();
|
||||
// setIsLoaded();
|
||||
// });
|
||||
// })
|
||||
// .catch((err) => toastr.error(err.message));
|
||||
// }, []);
|
||||
|
||||
const { isLoaded, loadBaseInfo, isThirdPartyResponse, modules } = rest;
|
||||
|
||||
useEffect(() => {
|
||||
@ -176,29 +190,45 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Current page ", page);
|
||||
// setModuleInfo(page, "e67be73d-f9ae-4ce1-8fec-1880cb518cb4");
|
||||
}, [page]);
|
||||
|
||||
const pathname = window.location.pathname.toLowerCase();
|
||||
const isEditor = pathname.indexOf("doceditor") !== -1;
|
||||
|
||||
const dynamicRoutes = modules
|
||||
.filter((m) => m.ready)
|
||||
.map((m) => {
|
||||
const system = {
|
||||
url: `${window.location.origin}${m.link}remoteEntry.js`,
|
||||
scope: m.appName,
|
||||
module: "./app",
|
||||
};
|
||||
return (
|
||||
<PrivateRoute
|
||||
key={m.id}
|
||||
path={`${homepage}${m.link}`}
|
||||
component={System}
|
||||
system={system}
|
||||
/>
|
||||
);
|
||||
});
|
||||
if (!window.AppServer.studio) {
|
||||
window.AppServer.studio = {};
|
||||
}
|
||||
|
||||
window.AppServer.studio.modules = {};
|
||||
|
||||
const dynamicRoutes = modules.map((m) => {
|
||||
const appURL = m.link;
|
||||
const remoteEntryURL = combineUrl(
|
||||
window.location.origin,
|
||||
appURL,
|
||||
"remoteEntry.js"
|
||||
);
|
||||
|
||||
const system = {
|
||||
url: remoteEntryURL,
|
||||
scope: m.appName,
|
||||
module: "./app",
|
||||
};
|
||||
|
||||
window.AppServer.studio.modules[m.appName] = {
|
||||
appURL,
|
||||
remoteEntryURL,
|
||||
};
|
||||
|
||||
return (
|
||||
<PrivateRoute
|
||||
key={m.id}
|
||||
path={appURL}
|
||||
component={System}
|
||||
system={system}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
@ -208,56 +238,27 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
|
||||
<ScrollToTop />
|
||||
<Main>
|
||||
<Switch>
|
||||
<PrivateRoute exact path={HOME_URLS} component={HomeRoute} />
|
||||
<PublicRoute exact path={WIZARD_URL} component={WizardRoute} />
|
||||
<PrivateRoute path={ABOUT_URL} component={AboutRoute} />
|
||||
<PublicRoute exact path={LOGIN_URLS} component={LoginRoute} />
|
||||
<Route path={CONFIRM_URL} component={ConfirmRoute} />
|
||||
<PrivateRoute
|
||||
exact
|
||||
path={[`${homepage}/`, `${homepage}/error=:error`]}
|
||||
component={HomeRoute}
|
||||
/>
|
||||
<PublicRoute
|
||||
exact
|
||||
path={`${homepage}/wizard`}
|
||||
component={WizardRoute}
|
||||
/>
|
||||
<PrivateRoute path={`${homepage}/about`} component={AboutRoute} />
|
||||
<PublicRoute
|
||||
exact
|
||||
path={[
|
||||
`${homepage}/login`,
|
||||
`${homepage}/login/error=:error`,
|
||||
`${homepage}/login/confirmed-email=:confirmedEmail`,
|
||||
]}
|
||||
component={LoginRoute}
|
||||
/>
|
||||
<Route path={`${homepage}/confirm`} component={ConfirmRoute} />
|
||||
<PrivateRoute
|
||||
path={[
|
||||
`${homepage}/coming-soon`,
|
||||
`${homepage}/products/mail`,
|
||||
`${homepage}/products/projects`,
|
||||
`${homepage}/products/crm`,
|
||||
`${homepage}/products/calendar`,
|
||||
`${homepage}/products/talk/`,
|
||||
]}
|
||||
path={COMING_SOON_URLS}
|
||||
component={ComingSoonRoute}
|
||||
/>
|
||||
<PrivateRoute
|
||||
path={`${homepage}/thirdparty/:provider`}
|
||||
path={THIRD_PARTY_RESPONSE_URL}
|
||||
component={ThirdPartyResponseRoute}
|
||||
/>
|
||||
<PrivateRoute
|
||||
path={`${homepage}/payments`}
|
||||
component={PaymentsRoute}
|
||||
/>
|
||||
<PrivateRoute path={PAYMENTS_URL} component={PaymentsRoute} />
|
||||
<PrivateRoute
|
||||
restricted
|
||||
path={`${homepage}/settings`}
|
||||
path={SETTINGS_URL}
|
||||
component={SettingsRoute}
|
||||
/>
|
||||
{dynamicRoutes}
|
||||
<PrivateRoute
|
||||
path={`${homepage}/error401`}
|
||||
component={Error401Route}
|
||||
/>
|
||||
<PrivateRoute path={ERROR_401_URL} component={Error401Route} />
|
||||
<PrivateRoute component={Error404Route} />
|
||||
</Switch>
|
||||
</Main>
|
||||
|
@ -3,12 +3,23 @@ import PropTypes from "prop-types";
|
||||
import styled from "styled-components";
|
||||
import NavItem from "./nav-item";
|
||||
import ProfileActions from "./profile-actions";
|
||||
//import history from "@appserver/common/history";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { tablet } from "@appserver/components/utils/device";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withRouter } from "react-router";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
import config from "../../../../package.json";
|
||||
|
||||
const { proxyURL } = AppServerConfig;
|
||||
const homepage = config.homepage;
|
||||
|
||||
const PROXY_HOMEPAGE_URL = combineUrl(proxyURL, homepage);
|
||||
const ABOUT_URL = combineUrl(PROXY_HOMEPAGE_URL, "/about");
|
||||
const PROFILE_URL = combineUrl(
|
||||
PROXY_HOMEPAGE_URL,
|
||||
"/products/people/view/@self"
|
||||
);
|
||||
|
||||
const StyledNav = styled.nav`
|
||||
display: flex;
|
||||
@ -41,10 +52,10 @@ const StyledNav = styled.nav`
|
||||
const HeaderNav = ({ history, modules, user, logout, isAuthenticated }) => {
|
||||
const { t } = useTranslation("NavMenu");
|
||||
const onProfileClick = useCallback(() => {
|
||||
history.push("/products/people/view/@self");
|
||||
history.push(PROFILE_URL);
|
||||
}, []);
|
||||
|
||||
const onAboutClick = useCallback(() => history.push("/about"), []);
|
||||
const onAboutClick = useCallback(() => history.push(ABOUT_URL), []);
|
||||
|
||||
const onLogoutClick = useCallback(() => logout && logout(), [logout]);
|
||||
|
||||
@ -54,13 +65,13 @@ const HeaderNav = ({ history, modules, user, logout, isAuthenticated }) => {
|
||||
key: "ProfileBtn",
|
||||
label: t("Profile"),
|
||||
onClick: onProfileClick,
|
||||
url: "/products/people/view/@self",
|
||||
url: PROFILE_URL,
|
||||
},
|
||||
{
|
||||
key: "AboutBtn",
|
||||
label: t("AboutCompanyTitle"),
|
||||
onClick: onAboutClick,
|
||||
url: "/about",
|
||||
url: ABOUT_URL,
|
||||
},
|
||||
{
|
||||
key: "LogoutBtn",
|
||||
|
@ -15,6 +15,9 @@ import Box from "@appserver/components/box";
|
||||
import Text from "@appserver/components/text";
|
||||
import { desktop } from "@appserver/components/utils/device";
|
||||
import i18n from "../i18n";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
const { proxyURL } = AppServerConfig;
|
||||
|
||||
const backgroundColor = "#0F4071";
|
||||
|
||||
@ -115,10 +118,7 @@ const HeaderComponent = ({
|
||||
|
||||
const onLogoClick = () => {
|
||||
history.push(defaultPage);
|
||||
};
|
||||
|
||||
const onLinkClick = () => {
|
||||
history.push("/about");
|
||||
backdropClick();
|
||||
};
|
||||
|
||||
const onBadgeClick = (e) => {
|
||||
@ -139,34 +139,34 @@ const HeaderComponent = ({
|
||||
};
|
||||
|
||||
//TODO: getCustomModules
|
||||
const getCustomModules = () => {
|
||||
if (!isAdmin) {
|
||||
return [];
|
||||
} // Temporarily hiding the settings module
|
||||
// const getCustomModules = () => {
|
||||
// if (!isAdmin) {
|
||||
// return [];
|
||||
// } // Temporarily hiding the settings module
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavItem
|
||||
separator={true}
|
||||
key={"nav-modules-separator"}
|
||||
data-id={"nav-modules-separator"}
|
||||
/>
|
||||
<NavItem
|
||||
separator={false}
|
||||
key={"settings"}
|
||||
data-id={"settings"}
|
||||
data-link="/settings"
|
||||
opened={isNavOpened}
|
||||
active={"settings" == currentProductId}
|
||||
iconName={"SettingsIcon"}
|
||||
onClick={onItemClick}
|
||||
url="/settings"
|
||||
>
|
||||
{t("Settings")}
|
||||
</NavItem>
|
||||
</>
|
||||
);
|
||||
};
|
||||
// return (
|
||||
// <>
|
||||
// <NavItem
|
||||
// separator={true}
|
||||
// key={"nav-modules-separator"}
|
||||
// data-id={"nav-modules-separator"}
|
||||
// />
|
||||
// <NavItem
|
||||
// separator={false}
|
||||
// key={"settings"}
|
||||
// data-id={"settings"}
|
||||
// data-link="/settings"
|
||||
// opened={isNavOpened}
|
||||
// active={"settings" == currentProductId}
|
||||
// iconName={"SettingsIcon"}
|
||||
// onClick={onItemClick}
|
||||
// url="/settings"
|
||||
// >
|
||||
// {t("Settings")}
|
||||
// </NavItem>
|
||||
// </>
|
||||
// );
|
||||
// };
|
||||
const isMainPage = pathname === "/";
|
||||
|
||||
return (
|
||||
@ -206,8 +206,7 @@ const HeaderComponent = ({
|
||||
{mainModules.map(
|
||||
({
|
||||
id,
|
||||
separator,
|
||||
iconName,
|
||||
separator, //iconName,
|
||||
iconUrl,
|
||||
notifications,
|
||||
link,
|
||||
@ -221,7 +220,7 @@ const HeaderComponent = ({
|
||||
data-link={link}
|
||||
opened={isNavOpened}
|
||||
active={isMainPage ? false : id == currentProductId}
|
||||
iconName={iconName}
|
||||
//iconName={iconName}
|
||||
iconUrl={iconUrl}
|
||||
badgeNumber={notifications}
|
||||
onClick={onItemClick}
|
||||
@ -248,7 +247,10 @@ const HeaderComponent = ({
|
||||
-{" "}
|
||||
</Text>
|
||||
<StyledLink>
|
||||
<LinkWithoutRedirect to="/about" className="nav-menu-header_link">
|
||||
<LinkWithoutRedirect
|
||||
to={combineUrl(proxyURL, "/about")}
|
||||
className="nav-menu-header_link"
|
||||
>
|
||||
{t("AboutShort")}
|
||||
</LinkWithoutRedirect>
|
||||
</StyledLink>
|
||||
@ -293,13 +295,13 @@ export default inject(({ auth }) => {
|
||||
const { logoUrl, defaultPage, currentProductId } = settingsStore;
|
||||
const { totalNotifications } = moduleStore;
|
||||
|
||||
const mainModules = availableModules.filter((m) => !m.isolateMode);
|
||||
//TODO: restore when chat will complete -> const mainModules = availableModules.filter((m) => !m.isolateMode);
|
||||
|
||||
return {
|
||||
isAdmin,
|
||||
defaultPage,
|
||||
logoUrl,
|
||||
mainModules,
|
||||
mainModules: availableModules,
|
||||
totalNotifications,
|
||||
isLoaded,
|
||||
version,
|
||||
|
@ -17,8 +17,11 @@ import PasswordInput from "@appserver/components/password-input";
|
||||
import toastr from "@appserver/components/toast/toastr";
|
||||
import Loader from "@appserver/components/loader";
|
||||
import PageLayout from "@appserver/common/components/PageLayout";
|
||||
import { EmployeeActivationStatus } from "@appserver/common/constants";
|
||||
import { createPasswordHash } from "@appserver/common/utils";
|
||||
import {
|
||||
AppServerConfig,
|
||||
EmployeeActivationStatus,
|
||||
} from "@appserver/common/constants";
|
||||
import { combineUrl, createPasswordHash } from "@appserver/common/utils";
|
||||
|
||||
const inputWidth = "400px";
|
||||
|
||||
@ -192,7 +195,7 @@ class Confirm extends React.PureComponent {
|
||||
|
||||
axios.all(requests).catch((e) => {
|
||||
console.error("get settings error", e);
|
||||
history.push(`/login/error=${e}`);
|
||||
history.push(combineUrl(AppServerConfig.proxyURL, `/login/error=${e}`));
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", this.onKeyPress);
|
||||
|
@ -14,7 +14,8 @@ import toastr from "@appserver/components/toast/toastr";
|
||||
import Loader from "@appserver/components/loader";
|
||||
import EmailInput from "@appserver/components/email-input";
|
||||
import PageLayout from "@appserver/common/components/PageLayout";
|
||||
import { createPasswordHash } from "@appserver/common/utils";
|
||||
import { combineUrl, createPasswordHash } from "@appserver/common/utils";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
||||
const inputWidth = "400px";
|
||||
|
||||
@ -185,7 +186,7 @@ class Confirm extends React.PureComponent {
|
||||
|
||||
axios.all(requests).catch((e) => {
|
||||
console.error("get settings error", e);
|
||||
history.push(`/login/error=${e}`);
|
||||
history.push(combineUrl(AppServerConfig.proxyURL, `/login/error=${e}`));
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", this.onKeyPress);
|
||||
|
@ -12,6 +12,8 @@ import {
|
||||
getTKeyByKey,
|
||||
checkPropertyByLink,
|
||||
} from "../../../utils";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
||||
const HeaderContainer = styled.div`
|
||||
position: relative;
|
||||
@ -86,7 +88,7 @@ class SectionHeaderContent extends React.Component {
|
||||
let newArrayOfParams = this.getArrayOfParams();
|
||||
newArrayOfParams.splice(-1, 1);
|
||||
const newPath = "/settings/" + newArrayOfParams.join("/");
|
||||
this.props.history.push(newPath);
|
||||
this.props.history.push(combineUrl(AppServerConfig.proxyURL, newPath));
|
||||
};
|
||||
|
||||
getArrayOfParams = () => {
|
||||
|
@ -8,8 +8,9 @@ import Link from "@appserver/components/link";
|
||||
import ArrowRightIcon from "../../../../../../public/images/arrow.right.react.svg";
|
||||
import { setDocumentTitle } from "../../../../../helpers/utils";
|
||||
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
|
||||
import { showLoader, hideLoader } from "@appserver/common/utils";
|
||||
import { showLoader, hideLoader, combineUrl } from "@appserver/common/utils";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
||||
const mapCulturesToArray = (cultures, t) => {
|
||||
return cultures.map((culture) => {
|
||||
@ -213,7 +214,10 @@ class Customization extends React.Component {
|
||||
className="inherit-title-link header"
|
||||
onClick={this.onClickLink}
|
||||
truncate={true}
|
||||
href="/settings/common/customization/language-and-time-zone"
|
||||
href={combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
"/settings/common/customization/language-and-time-zone"
|
||||
)}
|
||||
>
|
||||
{t("StudioTimeLanguageSettings")}
|
||||
</Link>
|
||||
@ -234,7 +238,10 @@ class Customization extends React.Component {
|
||||
truncate={true}
|
||||
className="inherit-title-link header"
|
||||
onClick={this.onClickLink}
|
||||
href="/settings/common/customization/custom-titles"
|
||||
href={combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
"/settings/common/customization/custom-titles"
|
||||
)}
|
||||
>
|
||||
{t("CustomTitles")}
|
||||
</Link>
|
||||
|
@ -10,6 +10,8 @@ import AdminsSettings from "./sub-components/admins";
|
||||
|
||||
import { setDocumentTitle } from "../../../../../helpers/utils";
|
||||
import { inject } from "mobx-react";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
||||
const MainContainer = styled.div`
|
||||
padding-bottom: 16px;
|
||||
@ -51,13 +53,23 @@ class PureAccessRights extends Component {
|
||||
|
||||
switch (page.key) {
|
||||
case "0":
|
||||
history.push("/settings/security/accessrights/owner");
|
||||
history.push(
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
"/settings/security/accessrights/owner"
|
||||
)
|
||||
);
|
||||
break;
|
||||
case "1":
|
||||
history.push("/settings/security/accessrights/admins");
|
||||
history.push(
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
"/settings/security/accessrights/admins"
|
||||
)
|
||||
);
|
||||
break;
|
||||
// case "2":
|
||||
// history.push("/settings/security/accessrights/modules");
|
||||
// history.push(combineUrl(AppServerConfig.proxyURL, "/settings/security/accessrights/modules"));
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
|
@ -8,7 +8,7 @@ import axios from "axios";
|
||||
import PageLayout from "@appserver/common/components/PageLayout";
|
||||
import ErrorContainer from "@appserver/common/components/ErrorContainer";
|
||||
import history from "@appserver/common/history";
|
||||
import { createPasswordHash } from "@appserver/common/utils";
|
||||
import { combineUrl, createPasswordHash } from "@appserver/common/utils";
|
||||
import Loader from "@appserver/components/loader";
|
||||
import { tablet } from "@appserver/components/utils/device";
|
||||
import { EmailSettings } from "@appserver/components/utils/email";
|
||||
@ -21,6 +21,7 @@ import ModalContainer from "./sub-components/modal-dialog-container";
|
||||
|
||||
import { setDocumentTitle } from "../../../helpers/utils";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
||||
const emailSettings = new EmailSettings();
|
||||
emailSettings.allowDomainPunycode = true;
|
||||
@ -95,7 +96,7 @@ class Body extends Component {
|
||||
window.addEventListener("keyup", this.onKeyPressHandler);
|
||||
|
||||
if (!wizardToken) {
|
||||
history.push("/");
|
||||
history.push(combineUrl(AppServerConfig.proxyURL, "/"));
|
||||
} else {
|
||||
await axios
|
||||
.all([
|
||||
@ -236,7 +237,9 @@ class Body extends Component {
|
||||
setWizardComplete();
|
||||
getPortalSettings();
|
||||
})
|
||||
.then(() => history.push("/login"))
|
||||
.then(() =>
|
||||
history.push(combineUrl(AppServerConfig.proxyURL, "/login"))
|
||||
)
|
||||
.catch((e) =>
|
||||
this.setState({
|
||||
errorLoading: true,
|
||||
|
@ -5,8 +5,9 @@ import { withRouter } from "react-router";
|
||||
import Loader from "@appserver/components/loader";
|
||||
import PageLayout from "@appserver/common/components/PageLayout";
|
||||
import { checkConfirmLink } from "@appserver/common/api/user"; //TODO: Move AuthStore
|
||||
import { getObjectByLocation } from "@appserver/common/utils";
|
||||
import { combineUrl, getObjectByLocation } from "@appserver/common/utils";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
||||
class ConfirmRoute extends React.Component {
|
||||
constructor(props) {
|
||||
@ -55,18 +56,26 @@ class ConfirmRoute extends React.Component {
|
||||
});
|
||||
break;
|
||||
case ValidationResult.Invalid:
|
||||
history.push(`${path}/error=Invalid link`);
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, path, "/error=Invalid link")
|
||||
);
|
||||
break;
|
||||
case ValidationResult.Expired:
|
||||
history.push(`${path}/error=Expired link`);
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, path, "/error=Expired link")
|
||||
);
|
||||
break;
|
||||
default:
|
||||
history.push(`${path}/error=Unknown error`);
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, path, "/error=Unknown error")
|
||||
);
|
||||
break;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
history.push(`${path}/error=${error}`);
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, path, `/error=${error}`)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
122
yarn.lock
@ -3504,9 +3504,9 @@
|
||||
loader-utils "^2.0.0"
|
||||
|
||||
"@tanem/svg-injector@^9.0.1":
|
||||
version "9.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@tanem/svg-injector/-/svg-injector-9.0.3.tgz#0aaa6664ce5ab9322b7e6c7ad2632cd991f5345f"
|
||||
integrity sha512-iRNGHmtL0k/gp0sAPTPYCadMnewZQpXIuFL+fGAAKpF1MkmROMCu7ZFR4uV9SqWYT/jelCcmSAFGc5OPqJc07A==
|
||||
version "9.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@tanem/svg-injector/-/svg-injector-9.0.4.tgz#0b0382f1569ca464da98f3a9be02fd0395e41bf4"
|
||||
integrity sha512-Urcvygj12r/xXwFfidmfGGepwkENyeLyjmQbAU19mF+sHgOL7dxd2pBC7iXgiaJo+4yYMBPa/Mqx+p/gQI2U6Q==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
content-type "^1.0.4"
|
||||
@ -3559,9 +3559,9 @@
|
||||
integrity sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==
|
||||
|
||||
"@types/babel__core@^7.1.0":
|
||||
version "7.1.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.13.tgz#bc6eea53975fdf163aff66c086522c6f293ae4cf"
|
||||
integrity sha512-CC6amBNND16pTk4K3ZqKIaba6VGKAQs3gMjEY17FVd56oI/ZWt9OhS6riYiWv9s8ENbYUi7p8lgqb0QHQvUKQQ==
|
||||
version "7.1.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
|
||||
integrity sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.1.0"
|
||||
"@babel/types" "^7.0.0"
|
||||
@ -3597,9 +3597,9 @@
|
||||
integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==
|
||||
|
||||
"@types/cheerio@^0.22.22":
|
||||
version "0.22.27"
|
||||
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.27.tgz#3a44d9b06fa40ca43599380cd0f3e2a1ceb98a57"
|
||||
integrity sha512-UpmYZewEWNEE6Ya24RzAQ2X2OYwz32AaLyzYinpM8qqFGRyYufqKSvxPjjZkvS+h16bajfXl7VojrAxWzG/+mA==
|
||||
version "0.22.28"
|
||||
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.28.tgz#90808aabb44fec40fa2950f4c72351e3e4eb065b"
|
||||
integrity sha512-ehUMGSW5IeDxJjbru4awKYMlKGmo1wSSGUVqXtYwlgmUM8X1a0PZttEIm6yEY7vHsY/hh6iPnklF213G0UColw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
@ -5839,9 +5839,9 @@ can-use-dom@^0.1.0:
|
||||
integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo=
|
||||
|
||||
caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001181:
|
||||
version "1.0.30001202"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001202.tgz#4cb3bd5e8a808e8cd89e4e66c549989bc8137201"
|
||||
integrity sha512-ZcijQNqrcF8JNLjzvEiXqX4JUYxoZa7Pvcsd9UD8Kz4TvhTonOSNRsK+qtvpVL4l6+T1Rh4LFtLfnNWg6BGWCQ==
|
||||
version "1.0.30001203"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001203.tgz#a7a34df21a387d9deffcd56c000b8cf5ab540580"
|
||||
integrity sha512-/I9tvnzU/PHMH7wBPrfDMSuecDeUKerjCPX7D0xBbaJZPxoT9m+yYxt0zCTkcijCkjTdim3H56Zm0i5Adxch4w==
|
||||
|
||||
capture-exit@^2.0.0:
|
||||
version "2.0.0"
|
||||
@ -6348,7 +6348,7 @@ compression@^1.7.4:
|
||||
safe-buffer "5.1.2"
|
||||
vary "~1.1.2"
|
||||
|
||||
compute-scroll-into-view@^1.0.16:
|
||||
compute-scroll-into-view@^1.0.17:
|
||||
version "1.0.17"
|
||||
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab"
|
||||
integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==
|
||||
@ -7160,10 +7160,10 @@ detect-newline@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
|
||||
integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=
|
||||
|
||||
detect-node-es@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.0.0.tgz#c0318b9e539a5256ca780dd9575c9345af05b8ed"
|
||||
integrity sha512-S4AHriUkTX9FoFvL4G8hXDcx6t3gp2HpfCza3Q0v6S78gul2hKWifLQbeW+ZF89+hSm2ZIc/uF3J97ZgytgTRg==
|
||||
detect-node-es@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
|
||||
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
|
||||
|
||||
detect-node@^2.0.4:
|
||||
version "2.0.5"
|
||||
@ -7429,12 +7429,12 @@ dotenv@^8.0.0:
|
||||
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
|
||||
|
||||
downshift@^6.0.6:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/downshift/-/downshift-6.1.0.tgz#f008063d9b63935910d9db12ead07979ab51ce66"
|
||||
integrity sha512-MnEJERij+1pTVAsOPsH3q9MJGNIZuu2sT90uxOCEOZYH6sEzkVGtUcTBVDRQkE8y96zpB7uEbRn24aE9VpHnZg==
|
||||
version "6.1.1"
|
||||
resolved "https://registry.yarnpkg.com/downshift/-/downshift-6.1.1.tgz#3c8f5a64cc678e1b45a87b80647ea5351af13e5e"
|
||||
integrity sha512-ch8Sh/j7gVqQd7Kcv3A5TkGfldmxmlQrRPZJYWEhzh24+h7WA4vXssuhcGNJrD8YPJlZYQGHcaX8BNhS0IcOvg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
compute-scroll-into-view "^1.0.16"
|
||||
compute-scroll-into-view "^1.0.17"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^17.0.1"
|
||||
|
||||
@ -7479,9 +7479,9 @@ ejs@^3.1.2:
|
||||
jake "^10.6.1"
|
||||
|
||||
electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.649:
|
||||
version "1.3.690"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.690.tgz#54df63ec42fba6b8e9e05fe4be52caeeedb6e634"
|
||||
integrity sha512-zPbaSv1c8LUKqQ+scNxJKv01RYFkVVF1xli+b+3Ty8ONujHjAMg+t/COmdZqrtnS1gT+g4hbSodHillymt1Lww==
|
||||
version "1.3.693"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.693.tgz#5089c506a925c31f93fcb173a003a22e341115dd"
|
||||
integrity sha512-vUdsE8yyeu30RecppQtI+XTz2++LWLVEIYmzeCaCRLSdtKZ2eXqdJcrs85KwLiPOPVc6PELgWyXBsfqIvzGZag==
|
||||
|
||||
element-resize-detector@^1.2.1:
|
||||
version "1.2.2"
|
||||
@ -7982,9 +7982,9 @@ events@^3.0.0, events@^3.2.0:
|
||||
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
|
||||
|
||||
eventsource@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0"
|
||||
integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf"
|
||||
integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==
|
||||
dependencies:
|
||||
original "^1.0.0"
|
||||
|
||||
@ -9202,10 +9202,10 @@ he@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
highlight.js@^10.1.1, highlight.js@~10.6.0:
|
||||
version "10.6.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.6.0.tgz#0073aa71d566906965ba6e1b7be7b2682f5e18b6"
|
||||
integrity sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ==
|
||||
highlight.js@^10.1.1, highlight.js@~10.7.0:
|
||||
version "10.7.1"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.1.tgz#a8ec4152db24ea630c90927d6cae2a45f8ecb955"
|
||||
integrity sha512-S6G97tHGqJ/U8DsXcEdnACbirtbx58Bx9CzIVeYli8OuswCfYI/LsXH2EiGcoGio1KAC3x4mmUwulOllJ2ZyRA==
|
||||
|
||||
highlight.js@~9.13.0:
|
||||
version "9.13.1"
|
||||
@ -9245,10 +9245,10 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.7.1:
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
|
||||
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
|
||||
|
||||
hosted-git-info@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.0.tgz#9f06639a90beff66cacae6e77f8387b431d61ddc"
|
||||
integrity sha512-fqhGdjk4av7mT9fU/B01dUtZ+WZSc/XEXMoLXDVZukiQRXxeHSSz3AqbeWRJHtF8EQYHlAgB1NSAHU0Cm7aqZA==
|
||||
hosted-git-info@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.1.tgz#710ef5452ea429a844abc33c981056e7371edab7"
|
||||
integrity sha512-eT7NrxAsppPRQEBSwKSosReE+v8OzABwEScQYk5d4uxaEPlzxTIku7LINXtBGalthkLhJnq5lBI89PfK43zAKg==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
@ -11369,12 +11369,12 @@ lower-case@^2.0.2:
|
||||
tslib "^2.0.3"
|
||||
|
||||
lowlight@^1.14.0:
|
||||
version "1.19.0"
|
||||
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.19.0.tgz#b8544199cafcf10c5731b21c7458c358f79a2a97"
|
||||
integrity sha512-NIskvQ1d1ovKyUytkMpT8+8Bhq3Ub54os1Xp4RAC9uNbXH1YVRf5NERq7JNzapEe5BzUc1Cj4F0I+eLBBFj6hA==
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888"
|
||||
integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==
|
||||
dependencies:
|
||||
fault "^1.0.0"
|
||||
highlight.js "~10.6.0"
|
||||
highlight.js "~10.7.0"
|
||||
|
||||
lowlight@~1.11.0:
|
||||
version "1.11.0"
|
||||
@ -12225,13 +12225,13 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-
|
||||
validate-npm-package-license "^3.0.1"
|
||||
|
||||
normalize-package-data@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.1.tgz#98dc56dfe6755d99b1c53f046e1e3d2dde55a1c7"
|
||||
integrity sha512-D/ttLdxo71msR4FF3VgSwK4blHfE3/vGByz1NCeE7/Dh8reQOKNJJjk5L10mLq9jxa+ZHzT1/HLgxljzbXE7Fw==
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699"
|
||||
integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==
|
||||
dependencies:
|
||||
hosted-git-info "^4.0.0"
|
||||
resolve "^1.17.0"
|
||||
semver "^7.3.2"
|
||||
hosted-git-info "^4.0.1"
|
||||
resolve "^1.20.0"
|
||||
semver "^7.3.4"
|
||||
validate-npm-package-license "^3.0.1"
|
||||
|
||||
normalize-path@^2.1.1:
|
||||
@ -13453,9 +13453,11 @@ qs@6.7.0:
|
||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||
|
||||
qs@^6.6.0, qs@^6.9.4:
|
||||
version "6.9.6"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee"
|
||||
integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==
|
||||
version "6.10.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.0.tgz#8b6519121ab291c316a3e4d49cecf6d13d8c7fe5"
|
||||
integrity sha512-yjACOWijC6L/kmPZZAsVBNY2zfHSIbpdpL977quseu56/8BZ2LoF5axK2bGhbzhVKt7V9xgWTtpyLbxwIoER0Q==
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
@ -14693,7 +14695,7 @@ resolve@1.1.7:
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
||||
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
|
||||
|
||||
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.3.2, resolve@^1.8.1, resolve@^1.9.0:
|
||||
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.3.2, resolve@^1.8.1, resolve@^1.9.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||
@ -14784,9 +14786,9 @@ rollup-pluginutils@^2.8.2:
|
||||
estree-walker "^0.6.1"
|
||||
|
||||
rollup@^2.25.0:
|
||||
version "2.41.4"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.41.4.tgz#2a674d64db4322482d440699acb060dc6dd9e65f"
|
||||
integrity sha512-f9IHfMO8p2Y8OdisI7Oj3oKkPuaQ6cgSwYqAi0TDvP3w2p+oX1VejX/w28a1h8WTnrapzfO5d4Uqhww+gL0b0g==
|
||||
version "2.42.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.42.1.tgz#6d675b7971e3bee510935326a0f7e556bb7d43de"
|
||||
integrity sha512-/y7M2ULg06JOXmMpPzhTeQroJSchy8lX8q6qrjqil0jmLz6ejCWbQzVnWTsdmMQRhfU0QcwtiW8iZlmrGXWV4g==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.1"
|
||||
|
||||
@ -14974,7 +14976,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.3.2:
|
||||
semver@^7.3.2, semver@^7.3.4:
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
|
||||
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
|
||||
@ -16113,9 +16115,9 @@ terser@^4.1.2, terser@^4.6.3, terser@^4.8.0:
|
||||
source-map-support "~0.5.12"
|
||||
|
||||
terser@^5.0.0, terser@^5.5.1:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.6.0.tgz#138cdf21c5e3100b1b3ddfddf720962f88badcd2"
|
||||
integrity sha512-vyqLMoqadC1uR0vywqOZzriDYzgEkNJFK4q9GeyOBHIbiECHiWLKcWfbQWAUaPfxkjDhapSlZB9f7fkMrvkVjA==
|
||||
version "5.6.1"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.6.1.tgz#a48eeac5300c0a09b36854bf90d9c26fb201973c"
|
||||
integrity sha512-yv9YLFQQ+3ZqgWCUk+pvNJwgUTdlIxUk1WTN+RnaFJe2L7ipG2csPT0ra2XRm7Cs8cxN7QXmK1rFzEwYEQkzXw==
|
||||
dependencies:
|
||||
commander "^2.20.0"
|
||||
source-map "~0.7.2"
|
||||
@ -16768,11 +16770,11 @@ use-latest@^1.0.0:
|
||||
use-isomorphic-layout-effect "^1.0.0"
|
||||
|
||||
use-sidecar@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.4.tgz#38398c3723727f9f924bed2343dfa3db6aaaee46"
|
||||
integrity sha512-A5ggIS3/qTdxCAlcy05anO2/oqXOfpmxnpRE1Jm+fHHtCvUvNSZDGqgOSAXPriBVAcw2fMFFkh5v5KqrFFhCMA==
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b"
|
||||
integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA==
|
||||
dependencies:
|
||||
detect-node-es "^1.0.0"
|
||||
detect-node-es "^1.1.0"
|
||||
tslib "^1.9.3"
|
||||
|
||||
use@^3.1.0:
|
||||
|