mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-30 08:54:31 +08:00
style global activities
This commit is contained in:
parent
685cb42aac
commit
3a2a1205e3
11 changed files with 190 additions and 54 deletions
|
@ -4,6 +4,7 @@ export const GET_LIST_OF_TEAMS = "GET_LIST_OF_TEAMS";
|
||||||
|
|
||||||
// activities
|
// activities
|
||||||
export const GLOBAL_ACTIVITIES_DATA = "GLOBAL_ACTIVITIES_DATA";
|
export const GLOBAL_ACTIVITIES_DATA = "GLOBAL_ACTIVITIES_DATA";
|
||||||
|
export const DESTROY_GLOBAL_ACTIVITIES_DATA = "DESTROY_GLOBAL_ACTIVITIES_DATA";
|
||||||
|
|
||||||
// users
|
// users
|
||||||
export const SET_CURRENT_USER = "SET_CURRENT_USER";
|
export const SET_CURRENT_USER = "SET_CURRENT_USER";
|
||||||
|
|
|
@ -3,3 +3,7 @@ export const WHITE_COLOR = "#fff";
|
||||||
export const BORDER_GRAY_COLOR = "#d2d2d2";
|
export const BORDER_GRAY_COLOR = "#d2d2d2";
|
||||||
export const WILD_SAND_COLOR = "#f5f5f5";
|
export const WILD_SAND_COLOR = "#f5f5f5";
|
||||||
export const MYSTIC_COLOR = "#eaeff2";
|
export const MYSTIC_COLOR = "#eaeff2";
|
||||||
|
export const COLOR_CONCRETE = "#f2f2f2";
|
||||||
|
export const COLOR_MINE_SHAFT = "#333"
|
||||||
|
export const COLOR_BLACK = "#000";
|
||||||
|
export const COLOR_GRAY_LIGHT_YADCF = "#ccc";
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import axios from "../../app/axios";
|
import axios from "../../app/axios";
|
||||||
import { ACTIVITIES_PATH } from "../../app/routes";
|
import { ACTIVITIES_PATH } from "../../app/routes";
|
||||||
import { GLOBAL_ACTIVITIES_DATA } from "../../app/action_types";
|
import {
|
||||||
|
GLOBAL_ACTIVITIES_DATA,
|
||||||
|
DESTROY_GLOBAL_ACTIVITIES_DATA
|
||||||
|
} from "../../app/action_types";
|
||||||
|
|
||||||
function addActivitiesData(data) {
|
function addActivitiesData(data) {
|
||||||
return {
|
return {
|
||||||
|
@ -9,9 +12,15 @@ function addActivitiesData(data) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getActivities(last_id = 0) {
|
export function destroyActivities() {
|
||||||
|
return {
|
||||||
|
type: DESTROY_GLOBAL_ACTIVITIES_DATA
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getActivities(lastId = 0) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
let path = `${ACTIVITIES_PATH}?from=${last_id}`;
|
const path = `${ACTIVITIES_PATH}?from=${lastId}`;
|
||||||
axios
|
axios
|
||||||
.get(path, { withCredentials: true })
|
.get(path, { withCredentials: true })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
|
@ -1,11 +1,34 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { FormattedDate } from "react-intl";
|
import Moment from "react-moment";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import { WHITE_COLOR } from "../../../app/constants/colors"
|
||||||
|
|
||||||
|
const StyledLi = styled.li`
|
||||||
|
margin-bottom: 1em;
|
||||||
|
`
|
||||||
|
|
||||||
|
const StyledSpan = styled.span`
|
||||||
|
display: inline;
|
||||||
|
padding: 5px 30px;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1;
|
||||||
|
color: ${WHITE_COLOR};
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: baseline;
|
||||||
|
border-radius: .25em;
|
||||||
|
`;
|
||||||
|
|
||||||
const ActivityDateElement = ({ date }) =>
|
const ActivityDateElement = ({ date }) =>
|
||||||
<li className="data-element">
|
<StyledLi className="text-center">
|
||||||
<FormattedDate value={date} day="2-digit" month="2-digit" year="numeric" />
|
<StyledSpan className="label label-primary">
|
||||||
</li>;
|
<Moment format="DD.MM.YYYY">
|
||||||
|
{date}
|
||||||
|
</Moment>
|
||||||
|
</StyledSpan>
|
||||||
|
</StyledLi>;
|
||||||
|
|
||||||
ActivityDateElement.propTypes = {
|
ActivityDateElement.propTypes = {
|
||||||
date: PropTypes.instanceOf(Date).isRequired
|
date: PropTypes.instanceOf(Date).isRequired
|
||||||
|
|
|
@ -1,24 +1,54 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { FormattedTime } from "react-intl";
|
import Moment from "react-moment";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import {
|
||||||
|
WHITE_COLOR,
|
||||||
|
COLOR_CONCRETE,
|
||||||
|
BORDER_GRAY_COLOR
|
||||||
|
} from "../../../app/constants/colors";
|
||||||
|
|
||||||
|
const StyledLi = styled.li`
|
||||||
|
border-radius: .25em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
background-color: ${WHITE_COLOR};
|
||||||
|
border: 1px solid ${COLOR_CONCRETE};
|
||||||
|
`;
|
||||||
|
const TimeSpan = styled.span`
|
||||||
|
min-width: 150px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-top-left-radius: .25em;
|
||||||
|
border-bottom-left-radius: .25em;
|
||||||
|
border: 3px solid ${BORDER_GRAY_COLOR};
|
||||||
|
background-color: ${BORDER_GRAY_COLOR};
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
vertical-align: top;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TextSpan = styled.span`
|
||||||
|
display: table-cell;
|
||||||
|
padding: 3px 10px;
|
||||||
|
text-align: justify;
|
||||||
|
`
|
||||||
|
|
||||||
const ActivityElement = ({ activity }) =>
|
const ActivityElement = ({ activity }) =>
|
||||||
<li>
|
<StyledLi>
|
||||||
<span>
|
<TimeSpan>
|
||||||
<FormattedTime
|
<Moment format="HH.mm">
|
||||||
value={activity.created_at}
|
{activity.created_at}
|
||||||
hour="numeric"
|
</Moment>
|
||||||
minute="numeric"
|
</TimeSpan>
|
||||||
/>
|
<TextSpan dangerouslySetInnerHTML={{ __html: activity.message }} />
|
||||||
</span>
|
</StyledLi>;
|
||||||
<span dangerouslySetInnerHTML={{ __html: activity.message }} />
|
|
||||||
</li>;
|
|
||||||
|
|
||||||
ActivityElement.propTypes = {
|
ActivityElement.propTypes = {
|
||||||
activity: PropTypes.shape({
|
activity: PropTypes.shape({
|
||||||
message: PropTypes.string.isRequired,
|
message: PropTypes.string.isRequired,
|
||||||
created_at: PropTypes.string.isRequired
|
created_at: PropTypes.string.isRequired
|
||||||
})
|
}).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ActivityElement;
|
export default ActivityElement;
|
||||||
|
|
|
@ -4,10 +4,46 @@ import PropTypes from "prop-types";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { Modal, Button } from "react-bootstrap";
|
import { Modal, Button } from "react-bootstrap";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { getActivities } from "../../actions/ActivitiesActions";
|
import { getActivities } from "../../actions/ActivitiesActions";
|
||||||
import ActivityElement from "./ActivityElement";
|
import ActivityElement from "./ActivityElement";
|
||||||
import ActivityDateElement from "./ActivityDateElement";
|
import ActivityDateElement from "./ActivityDateElement";
|
||||||
|
import {
|
||||||
|
WHITE_COLOR,
|
||||||
|
COLOR_CONCRETE,
|
||||||
|
COLOR_MINE_SHAFT,
|
||||||
|
COLOR_GRAY_LIGHT_YADCF
|
||||||
|
} from "../../../app/constants/colors";
|
||||||
|
|
||||||
|
const StyledBottom = styled(Button)`
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
touch-action: manipulation;
|
||||||
|
cursor: pointer;
|
||||||
|
background-image: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
color: ${COLOR_MINE_SHAFT};
|
||||||
|
background-color: ${WHITE_COLOR};
|
||||||
|
border-color: ${COLOR_GRAY_LIGHT_YADCF};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledModalBody = styled(Modal.Body)`
|
||||||
|
background-color: ${COLOR_CONCRETE};
|
||||||
|
color: ${COLOR_MINE_SHAFT};;
|
||||||
|
`;
|
||||||
|
|
||||||
class GlobalActivitiesModal extends Component {
|
class GlobalActivitiesModal extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -52,13 +88,14 @@ class GlobalActivitiesModal extends Component {
|
||||||
addMoreButton() {
|
addMoreButton() {
|
||||||
if (this.props.more) {
|
if (this.props.more) {
|
||||||
return (
|
return (
|
||||||
<li>
|
<li className="text-center">
|
||||||
<Button onClick={this.addMoreActivities}>
|
<StyledBottom onClick={this.addMoreActivities}>
|
||||||
<FormattedMessage id="activities.more_activities" />
|
<FormattedMessage id="activities.more_activities" />
|
||||||
</Button>
|
</StyledBottom>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -69,12 +106,12 @@ class GlobalActivitiesModal extends Component {
|
||||||
<FormattedMessage id="activities.modal_title" />
|
<FormattedMessage id="activities.modal_title" />
|
||||||
</Modal.Title>
|
</Modal.Title>
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
<Modal.Body>
|
<StyledModalBody>
|
||||||
<ul>
|
<ul className="list-unstyled">
|
||||||
{this.displayActivities()}
|
{this.displayActivities()}
|
||||||
{this.addMoreButton()}
|
{this.addMoreButton()}
|
||||||
</ul>
|
</ul>
|
||||||
</Modal.Body>
|
</StyledModalBody>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button onClick={this.props.onCloseModal}>
|
<Button onClick={this.props.onCloseModal}>
|
||||||
<FormattedMessage id="general.close" />
|
<FormattedMessage id="general.close" />
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
WHITE_COLOR,
|
WHITE_COLOR,
|
||||||
BORDER_GRAY_COLOR
|
BORDER_GRAY_COLOR
|
||||||
} from "../../app/constants/colors";
|
} from "../../app/constants/colors";
|
||||||
import { getActivities } from "../actions/ActivitiesActions";
|
import { getActivities, destroyActivities } from "../actions/ActivitiesActions";
|
||||||
import TeamSwitch from "./components/TeamSwitch";
|
import TeamSwitch from "./components/TeamSwitch";
|
||||||
import GlobalActivitiesModal from "./components/GlobalActivitiesModal";
|
import GlobalActivitiesModal from "./components/GlobalActivitiesModal";
|
||||||
import SearchDropdown from "./components/SearchDropdown";
|
import SearchDropdown from "./components/SearchDropdown";
|
||||||
|
@ -50,16 +50,29 @@ class Navigation extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
selectItemCallback(key, ev) {
|
selectItemCallback(key, ev) {
|
||||||
if (key === 4) {
|
switch (key) {
|
||||||
|
case 1:
|
||||||
|
window.location = "/";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
window.location = "/protocols";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
window.location = `/teams/${this.props.current_team.id}/repositories`;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.setState({ showActivitesModal: !this.state.showActivitesModal });
|
this.setState({ showActivitesModal: !this.state.showActivitesModal });
|
||||||
// Call action creator to fetch activities from the server
|
// Call action creator to fetch activities from the server
|
||||||
this.props.fetchActivities();
|
this.props.fetchActivities();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closeModalCallback() {
|
closeModalCallback() {
|
||||||
this.setState({ showActivitesModal: false });
|
this.setState({ showActivitesModal: false });
|
||||||
|
this.props.destroyActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -74,21 +87,16 @@ class Navigation extends Component {
|
||||||
</Navbar.Brand>
|
</Navbar.Brand>
|
||||||
</Navbar.Header>
|
</Navbar.Header>
|
||||||
<Nav>
|
<Nav>
|
||||||
<NavItem onClick={() => (window.location = "/")}>
|
<NavItem eventKey={1}>
|
||||||
<span className="glyphicon glyphicon-home" title="Home" />
|
<span className="glyphicon glyphicon-home" title="Home" />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<NavItem onClick={() => (window.location = "/protocols")}>
|
<NavItem eventKey={2}>
|
||||||
<span
|
<span
|
||||||
className="glyphicon glyphicon-list-alt"
|
className="glyphicon glyphicon-list-alt"
|
||||||
title="Protocol repositories"
|
title="Protocol repositories"
|
||||||
/>
|
/>
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<NavItem
|
<NavItem eventKey={3}>
|
||||||
eventKey={3}
|
|
||||||
onClick={() =>
|
|
||||||
(window.location = `/teams/${this.props.current_team
|
|
||||||
.id}/repositories`)}
|
|
||||||
>
|
|
||||||
<i
|
<i
|
||||||
className="fa fa-cubes"
|
className="fa fa-cubes"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
|
@ -121,6 +129,7 @@ class Navigation extends Component {
|
||||||
|
|
||||||
Navigation.propTypes = {
|
Navigation.propTypes = {
|
||||||
fetchActivities: PropTypes.func.isRequired,
|
fetchActivities: PropTypes.func.isRequired,
|
||||||
|
destroyActivities: PropTypes.func.isRequired,
|
||||||
current_team: PropTypes.shape({
|
current_team: PropTypes.shape({
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
|
@ -135,6 +144,9 @@ const mapStateToProps = ({ current_team }) => ({ current_team });
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
fetchActivities() {
|
fetchActivities() {
|
||||||
dispatch(getActivities());
|
dispatch(getActivities());
|
||||||
|
},
|
||||||
|
destroyActivities() {
|
||||||
|
dispatch(destroyActivities());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import {
|
import {
|
||||||
GLOBAL_ACTIVITIES_DATA,
|
GLOBAL_ACTIVITIES_DATA,
|
||||||
MORE_GLOBAL_ACTIVITIES
|
DESTROY_GLOBAL_ACTIVITIES_DATA
|
||||||
} from "../../app/action_types";
|
} from "../../app/action_types";
|
||||||
|
|
||||||
export function globalActivities(
|
const initialStateu = { more: true, activities: [] };
|
||||||
state = { more: true, activities: [] },
|
|
||||||
action
|
export function globalActivities(state = initialStateu, action) {
|
||||||
) {
|
switch (action.type) {
|
||||||
if (action.type === GLOBAL_ACTIVITIES_DATA) {
|
case GLOBAL_ACTIVITIES_DATA:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
activities: [
|
activities: [
|
||||||
|
@ -16,6 +16,12 @@ export function globalActivities(
|
||||||
],
|
],
|
||||||
more: action.payload.global_activities.more
|
more: action.payload.global_activities.more
|
||||||
};
|
};
|
||||||
}
|
case DESTROY_GLOBAL_ACTIVITIES_DATA:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...initialStateu
|
||||||
|
};
|
||||||
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,3 +6,7 @@ body {
|
||||||
font-family: "Open Sans",Arial,Helvetica,sans-serif;
|
font-family: "Open Sans",Arial,Helvetica,sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.label-primary {
|
||||||
|
background-color: $color-theme-primary;
|
||||||
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
"js-yaml": "^3.9.0",
|
"js-yaml": "^3.9.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
|
"moment": "^2.18.1",
|
||||||
"node-sass": "^4.5.3",
|
"node-sass": "^4.5.3",
|
||||||
"path-complete-extname": "^0.1.0",
|
"path-complete-extname": "^0.1.0",
|
||||||
"postcss-loader": "^2.0.6",
|
"postcss-loader": "^2.0.6",
|
||||||
|
@ -65,6 +66,7 @@
|
||||||
"react-dom": "^15.6.1",
|
"react-dom": "^15.6.1",
|
||||||
"react-intl": "^2.3.0",
|
"react-intl": "^2.3.0",
|
||||||
"react-intl-redux": "^0.6.0",
|
"react-intl-redux": "^0.6.0",
|
||||||
|
"react-moment": "^0.6.4",
|
||||||
"react-redux": "^5.0.5",
|
"react-redux": "^5.0.5",
|
||||||
"react-router-bootstrap": "^0.24.2",
|
"react-router-bootstrap": "^0.24.2",
|
||||||
"react-router-dom": "^4.1.2",
|
"react-router-dom": "^4.1.2",
|
||||||
|
|
|
@ -3596,6 +3596,10 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd
|
||||||
dependencies:
|
dependencies:
|
||||||
minimist "0.0.8"
|
minimist "0.0.8"
|
||||||
|
|
||||||
|
moment@^2.18.1:
|
||||||
|
version "2.18.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
|
||||||
|
|
||||||
ms@2.0.0:
|
ms@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
|
@ -4692,6 +4696,10 @@ react-intl@^2.3.0:
|
||||||
intl-relativeformat "^1.3.0"
|
intl-relativeformat "^1.3.0"
|
||||||
invariant "^2.1.1"
|
invariant "^2.1.1"
|
||||||
|
|
||||||
|
react-moment@^0.6.4:
|
||||||
|
version "0.6.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-moment/-/react-moment-0.6.4.tgz#5e531d47ad7b0bff6f6b7175093e98659f5e667b"
|
||||||
|
|
||||||
react-overlays@^0.7.0:
|
react-overlays@^0.7.0:
|
||||||
version "0.7.0"
|
version "0.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.0.tgz#531898ff566c7e5c7226ead2863b8cf9fbb5a981"
|
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.0.tgz#531898ff566c7e5c7226ead2863b8cf9fbb5a981"
|
||||||
|
|
Loading…
Add table
Reference in a new issue