This commit is contained in:
Andrey Savihin 2019-07-08 16:43:02 +03:00
commit f4b161b65f
26 changed files with 526 additions and 256 deletions

View File

@ -3,8 +3,12 @@ echo "ASC.Web.Components"
cd ../web/ASC.Web.Components
call npm install
echo "ASC.Web.Components Storybook"
cd ../ASC.Web.Components/example
call npm install
echo "ASC.Web.sln"
cd ../../
cd ../../../
call dotnet build ASC.Web.sln /fl1 /flp1:LogFile=build/ASC.Web.log;Verbosity=Normal
echo "ASC.People"

View File

@ -3,6 +3,7 @@ using System.Security.Authentication;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using ASC.Core;
using ASC.Web.Core;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
@ -26,6 +27,10 @@ namespace ASC.Web.Api.Handlers
{
var token = Context.Request.Cookies["asc_auth_key"] ?? Context.Request.Headers["Authorization"];
var result = SecurityContext.AuthenticateMe(token);
if (result)
{
Context.SetCookies(CookiesType.AuthKey, token);
}
return Task.FromResult(
result ?

View File

@ -68,7 +68,8 @@ namespace ASC.Common.DependencyInjection
void LoadAssembly(string type)
{
var dll = type.Substring(type.IndexOf(",") + 1).Trim();
var path = Directory.GetFiles(productsDir, $"{dll}.dll", SearchOption.AllDirectories).FirstOrDefault();
var productPath = Path.Combine(productsDir, dll);
var path = GetPath(Path.Combine(productPath, "bin"), dll, SearchOption.AllDirectories) ?? GetPath(productPath, dll, SearchOption.TopDirectoryOnly);
if (!string.IsNullOrEmpty(path))
{
@ -83,6 +84,13 @@ namespace ASC.Common.DependencyInjection
}
}
}
string GetPath(string dirPath, string dll, SearchOption searchOption)
{
if (!Directory.Exists(dirPath)) return null;
return Directory.GetFiles(dirPath, $"{dll}.dll", searchOption).FirstOrDefault();
}
}
}
}

View File

@ -2,18 +2,14 @@
using System.IO;
using System.Linq;
using System.Threading;
using ASC.Common.Utils;
using Newtonsoft.Json.Linq;
namespace ASC.Core.Common.Resources
{
public class JsonResourceManager
{
private static string DirName { get; set; }
static JsonResourceManager()
{
DirName = "ClientApp";
}
private const string ClientApp = "ClientApp";
private const string Locales = "locales";
public string FileName { get; }
@ -56,8 +52,8 @@ namespace ASC.Core.Common.Resources
JObject FromFile(string culture)
{
var dirPath = Path.GetFullPath(DirName);
if(!Directory.Exists(dirPath)) return new JObject();
var dirPath = GetDirName(Path.Combine(ClientApp, "build", Locales)) ?? GetDirName(Path.Combine(ClientApp, "public", Locales));
if(string.IsNullOrEmpty(dirPath)) return new JObject();
var files = Directory.GetFiles(dirPath, FileName, SearchOption.AllDirectories);
if (!files.Any()) return new JObject();
@ -67,5 +63,11 @@ namespace ASC.Core.Common.Resources
return JObject.Parse(File.ReadAllText(filePath));
}
string GetDirName(string dirName)
{
var dirPath = Path.GetFullPath(dirName);
return Directory.Exists(dirPath) ? dirPath : null;
}
}
}

View File

@ -42,46 +42,33 @@
location / {
proxy_pass http://localhost:5001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto "http";
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /api/2.0 {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto "http";
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /api/2.0/people {
proxy_pass http://localhost:5002;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto "http";
proxy_set_header X-REWRITER-URL $X_REWRITER_URL;
}
location /sockjs-node {
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_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

View File

@ -3,17 +3,32 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"bootstrap": "^4.3.1",
"asc-web-components": "file:../../../web/ASC.Web.Components/",
"axios": "^0.19.0",
"bootstrap": "4.3.1",
"connected-react-router": "6.5.0",
"history": "4.9.0",
"i18next": "17.0.6",
"i18next-browser-languagedetector": "3.0.1",
"i18next-xhr-backend": "3.0.0",
"jquery": "3.4.1",
"merge": "^1.2.1",
"oidc-client": "^1.7.1",
"node-sass": "^4.12.0",
"oidc-client": "^1.8.2",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-bootstrap": "^0.25.0",
"react-router-dom": "^5.0.0",
"react-scripts": "^3.0.1",
"reactstrap": "^8.0.0",
"rimraf": "^2.6.3"
"react-i18next": "10.11.3",
"react-redux": "7.1.0",
"react-router": "5.0.1",
"react-router-dom": "5.0.1",
"react-scripts": "3.0.1",
"reactstrap": "8.0.0",
"redux": "4.0.1",
"redux-thunk": "2.3.0",
"universal-cookie": "^4.0.0",
"lodash": "4.17.11",
"lodash-es": "4.17.11"
},
"devDependencies": {
"ajv": "^6.10.0",
@ -21,10 +36,12 @@
"cross-env": "^5.2.0",
"eslint": "^5.16.0",
"eslint-config-react-app": "^4.0.1",
"eslint-plugin-flowtype": "^3.9.0",
"eslint-plugin-import": "^2.17.2",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-react": "^7.13.0"
"eslint-plugin-flowtype": "^3.11.1",
"eslint-plugin-import": "^2.18.0",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.14.2",
"redux-devtools-extension": "^2.13.8",
"rimraf": "2.6.3"
},
"eslintConfig": {
"extends": "react-app"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -11,6 +11,7 @@
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i' rel='stylesheet' type='text/css'></link>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.

View File

@ -0,0 +1,26 @@
// Override default variables before the import
$font-family-base: 'Open Sans', sans-serif;
// Import Bootstrap and its default variables
@import '~bootstrap/scss/bootstrap.scss';
html, body {
height: 100%;
}
#root {
min-height: 100%;
position: relative;
main {
width: 100%;
height: 100%;
overflow: hidden;
.pageLoader {
position: fixed;
left: calc(50% - 32px);
top: 35%;
}
}
}

View File

@ -2,6 +2,7 @@ import 'bootstrap/dist/css/bootstrap.css';
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './custom.scss';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

View File

@ -71,7 +71,11 @@ namespace ASC.People
.AddWebItemManager()
.AddScoped<MessageService>()
.AddScoped<QueueWorkerReassign>()
.AddScoped<QueueWorkerRemove>();
.AddScoped<QueueWorkerRemove>()
.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@ -113,6 +117,19 @@ namespace ASC.People
app.UseCSP();
app.UseCm();
app.UseWebItemManager();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
}

View File

@ -237,7 +237,7 @@ const peopleContent = (userName, department, phone, email, headDepartment, statu
</Container>
)};
storiesOf('EXAMPLES|Row', module)
storiesOf('EXAMPLES|ContentRow', module)
.add('people row', () => {
return(

View File

@ -0,0 +1,21 @@
# ErrorContainer
## Usage
```js
import { ErrorContainer } from 'asc-web-components';
```
#### Description
Used to display full page error
#### Usage
```js
<ErrorContainer>Some error has happened</ErrorContainer>
```
#### Properties
Only children props is available

View File

@ -0,0 +1,16 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import withReadme from 'storybook-readme/with-readme'
import Readme from './README.md'
import { withKnobs, text } from '@storybook/addon-knobs/react';
import { Text, ErrorContainer } from 'asc-web-components';
storiesOf('Components| ErrorContainer', module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add('base', () => (
<ErrorContainer>
<Text.Headline tag="h2">{text("Headline text", "Some error has happened")}</Text.Headline>
<Text.Body tag="span">{text("Body text", "Try again later")}</Text.Body>
</ErrorContainer>
));

View File

@ -0,0 +1,69 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withKnobs, boolean, text, select, number } from '@storybook/addon-knobs/react';
import { BooleanValue, createBooleanValue } from 'react-values'
import withReadme from 'storybook-readme/with-readme'
import styled from '@emotion/styled';
import Readme from './README.md'
import { GroupButtonsMenu, Checkbox, DropDownItem, Button } from 'asc-web-components'
const GroupButtonsMenuContainer = styled.div`
height: 2000px;
`;
const createItems = (label, dropDownLabel, menuItemLabel, count) => {
var items =[
{
label: label,
isDropdown: true,
isSeparator: true,
fontWeight: 'bold',
children: [
<DropDownItem label={dropDownLabel}/>,
<DropDownItem label={dropDownLabel}/>,
<DropDownItem label={dropDownLabel}/>
]
}
];
for (var i=0; i<count; i++){
items.push({label:menuItemLabel});
}
return items;
}
storiesOf('Components|GroupButtonsMenu', module)
.addDecorator(withReadme(Readme))
.addDecorator(withKnobs)
.add('base', () => {
const elements = 10;
const selectLabel = 'Select';
const dropLabel = 'Dropdown item';
const menuItemLabel = 'Menu item';
const menuItems = createItems(selectLabel, dropLabel, menuItemLabel, elements);
return (
<GroupButtonsMenuContainer>
<GroupButtonsMenu checkBox={
<BooleanValue>
{({ value, toggle }) => (
<Checkbox isChecked={value}
onChange={e => {
console.log(e.target.value+' is checked');
toggle(e.target.checked);
}}
isDisabled={false}
value='Checkbox'
id='check1' />)}
</BooleanValue>}
menuItems={menuItems}
visible={true}
moreLabel={text('moreLabel', 'More')}
closeTitle={text('closeTitle', 'Close')}
/>
</GroupButtonsMenuContainer>
);
});

View File

@ -1,64 +0,0 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import withReadme from 'storybook-readme/with-readme'
import styled, { css } from '@emotion/styled';
import Readme from './README.md'
import { GroupButtonsMenu, GroupButton, DropDownItem } from 'asc-web-components'
const GroupButtonsMenuContainer = styled.div`
height: 2000px;
`;
const Checkbox = styled.input`
vertical-align: middle;
margin-left: 24px;
`;
storiesOf('Components|GroupButtonsMenu', module)
.addDecorator(withReadme(Readme))
.add('empty', () => (
<GroupButtonsMenuContainer>
<GroupButtonsMenu />
</GroupButtonsMenuContainer>
))
.add('documents', () => (
<GroupButtonsMenuContainer>
<GroupButtonsMenu needCollapse>
<Checkbox name="checkbox" type="checkbox" />
<GroupButton label='Select' isDropdown isSeparator fontWeight='bold'>
<DropDownItem label='All'/>
<DropDownItem label='Files'/>
<DropDownItem label='Folders'/>
<DropDownItem label='Documents'/>
<DropDownItem label='Presentations'/>
<DropDownItem label='Images'/>
<DropDownItem label='Archives'/>
</GroupButton>
<GroupButton label='Share'/>
<GroupButton label='Download' />
<GroupButton label='Download as'/>
<GroupButton label='Move'/>
<GroupButton label='Copy'/>
<GroupButton label='Delete'/>
</GroupButtonsMenu>
</GroupButtonsMenuContainer>
))
.add('people', () => (
<GroupButtonsMenuContainer>
<GroupButtonsMenu needCollapse>
<Checkbox name="checkbox" type="checkbox" />
<GroupButton label='Select' isDropdown isSeparator fontWeight='bold'>
<DropDownItem label='Active'/>
<DropDownItem label='Disabled'/>
<DropDownItem label='Invited'/>
</GroupButton>
<GroupButton label='Make employee' />
<GroupButton label='Make guest' />
<GroupButton label='Set active' />
<GroupButton label='Set disabled' />
<GroupButton label='Invite again' />
<GroupButton label='Send e-mail' />
<GroupButton label='Delete' />
</GroupButtonsMenu>
</GroupButtonsMenuContainer>
));

View File

@ -0,0 +1,76 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withKnobs, text} from '@storybook/addon-knobs/react';
import { BooleanValue } from 'react-values'
import styled from '@emotion/styled';
import { GroupButtonsMenu, Checkbox, DropDownItem } from 'asc-web-components'
const GroupButtonsMenuContainer = styled.div`
height: 2000px;
`;
const peopleItems = [
{
label: 'Select',
isDropdown: true,
isSeparator: true,
fontWeight: 'bold',
children: [
<DropDownItem label='Active'/>,
<DropDownItem label='Disabled'/>,
<DropDownItem label='Invited'/>
]
},
{
label: 'Make employee',
action: () => console.log('Make employee action')
},
{
label: 'Make guest',
action: () => console.log('Make guest action')
},
{
label: 'Set active',
action: () => console.log('Set active action')
},
{
label: 'Set disabled',
action: () => console.log('Set disabled action')
},
{
label: 'Invite again',
action: () => console.log('Invite again action')
},
{
label: 'Send e-mail',
action: () => console.log('Send e-mail action')
},
{
label: 'Delete',
action: () => console.log('Delete action')
}
];
storiesOf('EXAMPLES|GroupButtonsMenu', module)
.addDecorator(withKnobs)
.add('people', () => (
<GroupButtonsMenuContainer>
<GroupButtonsMenu checkBox={
<BooleanValue>
{({ value, toggle }) => (
<Checkbox isChecked={value}
onChange={e => {
console.log(e.target.value);
toggle(e.target.checked);
}}
isDisabled={false}
value='Checkbox'
id='check1' />)}
</BooleanValue>}
menuItems={peopleItems}
visible={true}
moreLabel={text('moreLabel', 'More')}
closeTitle={text('closeTitle', 'Close')}
/>
</GroupButtonsMenuContainer>
));

View File

@ -16,6 +16,7 @@ const StyledDropdownItem = styled.button`
margin: ${props => (props.isSeparator ? '0 16px' : '0')};
padding: ${props => (props.isUserPreview ? '0px' : '0 16px')};
text-decoration: none;
display: block;
user-select: none;
-o-user-select: none;

File diff suppressed because one or more lines are too long

View File

@ -3,6 +3,7 @@ import styled, { css } from 'styled-components'
import PropTypes from 'prop-types'
import { Icons } from '../icons'
import DropDown from '../drop-down'
import Checkbox from '../checkbox'
const textColor = '#333333',
disabledTextColor = '#A3A9AE';
@ -88,7 +89,7 @@ const useOuterClickNotifier = (onOuterClick, ref) => {
}
const GroupButton = (props) => {
const { label, isDropdown, opened, disabled, action, isSeparator } = props;
const { label, isDropdown, opened, disabled, action, isSeparator} = props;
const [isOpen, toggle] = useState(opened);
const ref = useRef(null);

View File

@ -1,7 +1,8 @@
import React, { useState, useEffect, useRef } from 'react'
import React from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import GroupButton from '../group-button'
import DropDownItem from '../drop-down-item'
const StyledGroupButtonsMenu = styled.div`
position: sticky;
@ -11,10 +12,9 @@ const StyledGroupButtonsMenu = styled.div`
height: 56px;
list-style: none;
padding: 0 18px 19px 0;
.hidden {
display: none;
}
width: 100%;
white-space: nowrap;
display: ${state => state.visible ? 'block' : 'none'};
`;
const CloseButton = styled.div`
@ -46,84 +46,108 @@ const CloseButton = styled.div`
}
`;
const padding = 4;
var lastWidth = 0;
const CheckBox = styled.div`
display: inline-block;
margin-left: 20px;
vertical-align: middle;
const collapseButtons = (menu) => {
if (menu == undefined) return;
& > * {
margin: 0px;
}
`;
class GroupButtonsMenu extends React.Component {
constructor(props) {
super(props);
this.updateMenu = this.updateMenu.bind(this);
this.state = {
priorityItems: [],
moreItems: [],
visible: true
}
this.fullMenuArray = this.props.menuItems;
this.checkBox = this.props.checkBox;
}
var groupMenu = menu,
groupMenuWidth = groupMenu.clientWidth,
groupButtons = groupMenu.querySelectorAll('div[class*="-0"]:not(.more):not(.hidden)'),
groupButtonsMore = groupMenu.querySelector('div.more[class*="-0"]'),
groupButtonsMoreWidth = groupButtonsMore.clientWidth || 0,
groupButtonsWidthArray = getButtonsWidthArray(groupButtons),
groupButtonsWidth = getButtonsWidth(groupButtonsWidthArray),
lastHidden = getLastHidden(groupMenu),
lastHiddenWidth = (lastHidden != undefined) ? lastHidden.clientWidth : 0,
lastGroupButton = groupButtons[groupButtons.length -1],
moreThanMenu = groupButtonsWidth + groupButtonsMoreWidth - lastHiddenWidth,
lessThanMenu = groupButtonsWidth + groupButtonsMoreWidth + lastHiddenWidth + lastGroupButton.clientWidth * 1.3;
if (lastWidth !== 0 && lastWidth > groupMenuWidth){
if (moreThanMenu > groupMenuWidth) {
lastGroupButton.classList.add('hidden');
}
} else {
if (lessThanMenu < groupMenuWidth && lastHidden != undefined) {
lastHidden.classList.remove('hidden');
}
componentWillMount() {
this.setState({
priorityItems: this.props.menuItems
})
}
if (lastHidden == undefined){
groupButtonsMore.classList.add('hidden');
} else {
groupButtonsMore.classList.remove('hidden');
componentDidMount() {
this.widthsArray = Array.from(this.refs.groupMenu.children).map(item => item.getBoundingClientRect().width);
window.addEventListener('resize', _.throttle(this.updateMenu), 100);
this.updateMenu();
}
howManyItemsInMenuArray(array, outerWidth, initialWidth, minimumNumberInNav) {
let total = (initialWidth+150);
for(let i = 0; i < array.length; i++) {
if(total + array[i] > outerWidth) {
return i < minimumNumberInNav ? minimumNumberInNav : i;
} else {
total += array[i];
}
}
}
lastWidth = groupMenuWidth;
}
updateMenu() {
this.outerWidth = this.refs.groupMenuOuter ? this.refs.groupMenuOuter.getBoundingClientRect().width : 0;
this.moreMenu = this.refs.moreMenu ? this.refs.moreMenu.getBoundingClientRect().width : 0;
const getButtonsWidthArray = (buttons) => {
return Array.prototype.slice.call(buttons).map((button => button.clientWidth + padding * 2));
}
const arrayAmount = this.howManyItemsInMenuArray(this.widthsArray, this.outerWidth, this.moreMenu, 1);
const navItemsCopy = this.fullMenuArray;
const priorityItems = navItemsCopy.slice(0, arrayAmount);
this.setState({
priorityItems: priorityItems,
moreItems: priorityItems.length !== navItemsCopy.length ? navItemsCopy.slice(arrayAmount, navItemsCopy.length) : []
});
}
const getButtonsWidth = (buttonsWidthArray) => {
return buttonsWidthArray.reduce((a,b) => a + b);
}
componentWillUnmount() {
window.removeEventListener('resize', this.updateMenu());
}
const getLastHidden = (buttons) => {
return buttons.querySelectorAll('div[class*="-0"].hidden:not(.more)')[0];
}
render() {
const { priorityItems, moreItems } = this.state;
const GroupButtonsMenu = props => {
const { children, needCollapse } = props;
const ref = useRef(null);
const toggle = () => this.setState({visible: !this.props.visible});
const collapseEvent = (e) => (React.Children.toArray(props.children).length && needCollapse)
? collapseButtons(ref.current)
: e.preventDefault();
useEffect(() => {
window.addEventListener('load', collapseEvent(event));
window.onresize = (e) => collapseEvent(e);
});
return (
<StyledGroupButtonsMenu ref={ref} {...props}>
{children}
{needCollapse && <GroupButton className="more" isDropdown label='More'>{children}</GroupButton>}
<CloseButton/>
</StyledGroupButtonsMenu>
);
}
GroupButtonsMenu.propTypes = {
needCollapse: PropTypes.bool
}
GroupButtonsMenu.defaultProps = {
needCollapse: false
return (
<StyledGroupButtonsMenu ref="groupMenuOuter" visible={this.state.visible} {...this.state}>
{this.checkBox &&
<CheckBox>{this.checkBox}</CheckBox>
}
<div ref="groupMenu" style={{display: 'inline-block'}}>
{priorityItems.map((item, i) =>
<GroupButton key={`navItem-${i}`}
label={item.label}
isDropdown={item.isDropdown}
isSeparator={item.isSeparator}
fontWeight={item.fontWeight}
action={item.action}>
{item.children}
</GroupButton>
)}
</div>
{moreItems.length > 0 &&
<GroupButton ref="moreMenu" isDropdown label={this.props.moreLabel}>
{moreItems.map((item, i) =>
<DropDownItem
key={`moreNavItem-${i}`}
label={item.label}
onClick={item.onClick} />
)}
</GroupButton>
}
<CloseButton title={this.props.closeTitle} onClick={() => toggle()} />
</StyledGroupButtonsMenu>
);
}
}
export default GroupButtonsMenu;

View File

@ -1,26 +1,24 @@
import React from 'react';
import React, {useState, useRef, useEffect} from 'react';
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
import { Icons } from '../icons'
const SimpleLink = ({ rel, isBold, fontSize, isTextOverflow, isHovered, isSemitransparent, type, color, text, target, dropdownType, ...props }) => <a {...props}>{text}</a>;
const arrowDropdown = css`
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: ${props =>
(props.color === 'black' && '4px solid #333333') ||
(props.color === 'gray' && '4px solid #A3A9AE') ||
(props.color === 'blue' && '4px solid #316DAA')
};
content: "";
height: 0;
position: absolute;
right: -15px;
top: 1px;
bottom: 0px;
top: 50%;
width: 0;
margin-top: -2px;
const getDropdownColor = color => {
switch (color) {
case 'gray':
return '#A3A9AE';
case 'blue':
return '#316DAA';
default:
return '#333333';
}
}
const opacityCss = css `
opacity: ${props =>
(props.isSemitransparent && '0.5')};
`;
const colorCss = css`
@ -45,6 +43,13 @@ const dottedCss = css`
border-bottom: 1px dotted;
`;
const Caret = styled(Icons.ExpanderDownIcon)`
width: 10px;
margin-left: 5px;
margin-top: -4px;
${opacityCss};
`;
const StyledLink = styled(SimpleLink).attrs((props) => ({
href: props.href,
target: props.target,
@ -52,6 +57,7 @@ const StyledLink = styled(SimpleLink).attrs((props) => ({
title: props.title
}))`
${colorCss};
${opacityCss};
font-size: ${props => props.fontSize}px;
cursor: pointer;
position: relative;
@ -91,13 +97,6 @@ ${props => (props.type === 'action' && (props.isHovered || props.dropdownType ==
${dottedCss}
`)
}
${props => (props.type === 'action' && props.dropdownType === 'alwaysDotted' &&
css`
&:after {
${arrowDropdown}
}`)
}
${props => (props.isTextOverflow &&
css`
@ -110,26 +109,20 @@ ${props => (props.isTextOverflow &&
`)
}
${props => (props.type === 'action' && props.dropdownType === 'appearDottedAfterHover' &&
css`
&:hover {
:after {
${arrowDropdown}
}
}
`)
}
${props => (props.isSemitransparent
&&
css`
opacity: 0.5;
`)
}
`;
const Link = props => <StyledLink {...props} />;
const Link = props => {
const [isHovered, toggle] = useState(false);
return (
<span
onMouseEnter={() => {props.dropdownType === 'appearDottedAfterHover' && toggle(!isHovered)}}
onMouseLeave={() => {props.dropdownType === 'appearDottedAfterHover' && toggle(!isHovered)}}>
<StyledLink {...props} />
{(props.dropdownType === 'alwaysDotted' || (isHovered && props.dropdownType === 'appearDottedAfterHover')) && <Caret {...props} size='small' isfill={true} color={getDropdownColor(props.color)} /> }
</span>
);
}
Link.propTypes = {
color: PropTypes.oneOf(['gray', 'black', 'blue']),
@ -149,6 +142,7 @@ Link.propTypes = {
Link.defaultProps = {
color: 'black',
dropdownType: 'none',
fontSize: 12,
href: undefined,
isBold: false,

View File

@ -22,4 +22,5 @@ export { Text } from './components/text'
export { default as ModalDialog } from './components/modal-dialog'
export { default as Layout } from './components/layout'
export { default as ContentRow } from './components/content-row'
export { default as Badge } from './components/badge'
export { default as Badge } from './components/badge'
export { default as ErrorContainer } from './components/error-container'

View File

@ -27,6 +27,7 @@
using System;
using System.Linq;
using System.Security;
using System.Web;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
@ -71,36 +72,45 @@ namespace ASC.Web.Core
{
if (httpContext == null) return;
//TODO
//httpContext.Response.Cookies[GetCookiesName(type)].Value = value;
//httpContext.Response.Cookies[GetCookiesName(type)].Expires = GetExpiresDate(session);
var options = new CookieOptions
{
Expires = GetExpiresDate(session)
};
//if (type == CookiesType.AuthKey)
//{
// httpContext.Response.Cookies[GetCookiesName(type)].HttpOnly = true;
if (type == CookiesType.AuthKey)
{
options.HttpOnly = true;
// if (httpContext.Request.GetUrlRewriter().Scheme == "https")
// httpContext.Response.Cookies[GetCookiesName(type)].Secure = true;
if (httpContext.Request.GetUrlRewriter().Scheme == "https")
{
options.Secure = true;
}
}
//}
httpContext.Response.Cookies.Append(GetCookiesName(type), value, options);
}
public static void SetCookies(this HttpContext httpContext, CookiesType type, string value, string domain, bool session = false)
{
if (httpContext == null) return;
//TODO
//httpContext.Response.Cookies[GetCookiesName(type)].Value = value;
//httpContext.Response.Cookies[GetCookiesName(type)].Domain = domain;
//httpContext.Response.Cookies[GetCookiesName(type)].Expires = GetExpiresDate(session);
var options = new CookieOptions
{
Expires = GetExpiresDate(session),
Domain = domain
};
//if (type == CookiesType.AuthKey)
//{
// httpContext.Response.Cookies[GetCookiesName(type)].HttpOnly = true;
if (type == CookiesType.AuthKey)
{
options.HttpOnly = true;
// if (httpContext.Request.GetUrlRewriter().Scheme == "https")
// httpContext.Response.Cookies[GetCookiesName(type)].Secure = true;
//}
if (httpContext.Request.GetUrlRewriter().Scheme == "https")
{
options.Secure = true;
}
}
httpContext.Response.Cookies.Append(GetCookiesName(type), value, options);
}
public static string GetCookies(this HttpContext httpContext, CookiesType type)
@ -109,9 +119,8 @@ namespace ASC.Web.Core
{
var cookieName = GetCookiesName(type);
//TODO
//if (httpContext.Request.Cookies[cookieName] != null)
// return httpContext.Request.Cookies[cookieName].Value ?? "";
if (httpContext.Request.Cookies.ContainsKey(cookieName))
return httpContext.Request.Cookies[cookieName] ?? "";
}
return "";
}
@ -120,9 +129,10 @@ namespace ASC.Web.Core
{
if (httpContext == null) return;
//TODO
//if (httpContext.Request.Cookies[GetCookiesName(type)] != null)
// httpContext.Response.Cookies[GetCookiesName(type)].Expires = DateTime.Now.AddDays(-3);
if (httpContext.Request.Cookies.ContainsKey(GetCookiesName(type)))
{
httpContext.Response.Cookies.Delete(GetCookiesName(type), new CookieOptions() { Expires = DateTime.Now.AddDays(-3) });
}
}
private static DateTime GetExpiresDate(bool session)