mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-30 00:45:28 +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
|
||||
export const GLOBAL_ACTIVITIES_DATA = "GLOBAL_ACTIVITIES_DATA";
|
||||
export const DESTROY_GLOBAL_ACTIVITIES_DATA = "DESTROY_GLOBAL_ACTIVITIES_DATA";
|
||||
|
||||
// users
|
||||
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 WILD_SAND_COLOR = "#f5f5f5";
|
||||
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 { 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) {
|
||||
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 => {
|
||||
let path = `${ACTIVITIES_PATH}?from=${last_id}`;
|
||||
const path = `${ACTIVITIES_PATH}?from=${lastId}`;
|
||||
axios
|
||||
.get(path, { withCredentials: true })
|
||||
.then(response => {
|
||||
|
|
|
@ -1,11 +1,34 @@
|
|||
import React from "react";
|
||||
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 }) =>
|
||||
<li className="data-element">
|
||||
<FormattedDate value={date} day="2-digit" month="2-digit" year="numeric" />
|
||||
</li>;
|
||||
<StyledLi className="text-center">
|
||||
<StyledSpan className="label label-primary">
|
||||
<Moment format="DD.MM.YYYY">
|
||||
{date}
|
||||
</Moment>
|
||||
</StyledSpan>
|
||||
</StyledLi>;
|
||||
|
||||
ActivityDateElement.propTypes = {
|
||||
date: PropTypes.instanceOf(Date).isRequired
|
||||
|
|
|
@ -1,24 +1,54 @@
|
|||
import React from "react";
|
||||
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 }) =>
|
||||
<li>
|
||||
<span>
|
||||
<FormattedTime
|
||||
value={activity.created_at}
|
||||
hour="numeric"
|
||||
minute="numeric"
|
||||
/>
|
||||
</span>
|
||||
<span dangerouslySetInnerHTML={{ __html: activity.message }} />
|
||||
</li>;
|
||||
<StyledLi>
|
||||
<TimeSpan>
|
||||
<Moment format="HH.mm">
|
||||
{activity.created_at}
|
||||
</Moment>
|
||||
</TimeSpan>
|
||||
<TextSpan dangerouslySetInnerHTML={{ __html: activity.message }} />
|
||||
</StyledLi>;
|
||||
|
||||
ActivityElement.propTypes = {
|
||||
activity: PropTypes.shape({
|
||||
message: PropTypes.string.isRequired,
|
||||
created_at: PropTypes.string.isRequired
|
||||
})
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
export default ActivityElement;
|
||||
|
|
|
@ -4,10 +4,46 @@ import PropTypes from "prop-types";
|
|||
import { FormattedMessage } from "react-intl";
|
||||
import { Modal, Button } from "react-bootstrap";
|
||||
import _ from "lodash";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { getActivities } from "../../actions/ActivitiesActions";
|
||||
import ActivityElement from "./ActivityElement";
|
||||
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 {
|
||||
constructor(props) {
|
||||
|
@ -52,13 +88,14 @@ class GlobalActivitiesModal extends Component {
|
|||
addMoreButton() {
|
||||
if (this.props.more) {
|
||||
return (
|
||||
<li>
|
||||
<Button onClick={this.addMoreActivities}>
|
||||
<li className="text-center">
|
||||
<StyledBottom onClick={this.addMoreActivities}>
|
||||
<FormattedMessage id="activities.more_activities" />
|
||||
</Button>
|
||||
</StyledBottom>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -69,12 +106,12 @@ class GlobalActivitiesModal extends Component {
|
|||
<FormattedMessage id="activities.modal_title" />
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<ul>
|
||||
<StyledModalBody>
|
||||
<ul className="list-unstyled">
|
||||
{this.displayActivities()}
|
||||
{this.addMoreButton()}
|
||||
</ul>
|
||||
</Modal.Body>
|
||||
</StyledModalBody>
|
||||
<Modal.Footer>
|
||||
<Button onClick={this.props.onCloseModal}>
|
||||
<FormattedMessage id="general.close" />
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
WHITE_COLOR,
|
||||
BORDER_GRAY_COLOR
|
||||
} from "../../app/constants/colors";
|
||||
import { getActivities } from "../actions/ActivitiesActions";
|
||||
import { getActivities, destroyActivities } from "../actions/ActivitiesActions";
|
||||
import TeamSwitch from "./components/TeamSwitch";
|
||||
import GlobalActivitiesModal from "./components/GlobalActivitiesModal";
|
||||
import SearchDropdown from "./components/SearchDropdown";
|
||||
|
@ -50,16 +50,29 @@ class Navigation extends Component {
|
|||
}
|
||||
|
||||
selectItemCallback(key, ev) {
|
||||
if (key === 4) {
|
||||
ev.preventDefault();
|
||||
this.setState({ showActivitesModal: !this.state.showActivitesModal });
|
||||
// Call action creator to fetch activities from the server
|
||||
this.props.fetchActivities();
|
||||
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();
|
||||
this.setState({ showActivitesModal: !this.state.showActivitesModal });
|
||||
// Call action creator to fetch activities from the server
|
||||
this.props.fetchActivities();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
closeModalCallback() {
|
||||
this.setState({ showActivitesModal: false });
|
||||
this.props.destroyActivities();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -74,21 +87,16 @@ class Navigation extends Component {
|
|||
</Navbar.Brand>
|
||||
</Navbar.Header>
|
||||
<Nav>
|
||||
<NavItem onClick={() => (window.location = "/")}>
|
||||
<NavItem eventKey={1}>
|
||||
<span className="glyphicon glyphicon-home" title="Home" />
|
||||
</NavItem>
|
||||
<NavItem onClick={() => (window.location = "/protocols")}>
|
||||
<NavItem eventKey={2}>
|
||||
<span
|
||||
className="glyphicon glyphicon-list-alt"
|
||||
title="Protocol repositories"
|
||||
/>
|
||||
</NavItem>
|
||||
<NavItem
|
||||
eventKey={3}
|
||||
onClick={() =>
|
||||
(window.location = `/teams/${this.props.current_team
|
||||
.id}/repositories`)}
|
||||
>
|
||||
<NavItem eventKey={3}>
|
||||
<i
|
||||
className="fa fa-cubes"
|
||||
aria-hidden="true"
|
||||
|
@ -121,6 +129,7 @@ class Navigation extends Component {
|
|||
|
||||
Navigation.propTypes = {
|
||||
fetchActivities: PropTypes.func.isRequired,
|
||||
destroyActivities: PropTypes.func.isRequired,
|
||||
current_team: PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
|
@ -135,6 +144,9 @@ const mapStateToProps = ({ current_team }) => ({ current_team });
|
|||
const mapDispatchToProps = dispatch => ({
|
||||
fetchActivities() {
|
||||
dispatch(getActivities());
|
||||
},
|
||||
destroyActivities() {
|
||||
dispatch(destroyActivities());
|
||||
}
|
||||
});
|
||||
|
|
@ -1,21 +1,27 @@
|
|||
import {
|
||||
GLOBAL_ACTIVITIES_DATA,
|
||||
MORE_GLOBAL_ACTIVITIES
|
||||
DESTROY_GLOBAL_ACTIVITIES_DATA
|
||||
} from "../../app/action_types";
|
||||
|
||||
export function globalActivities(
|
||||
state = { more: true, activities: [] },
|
||||
action
|
||||
) {
|
||||
if (action.type === GLOBAL_ACTIVITIES_DATA) {
|
||||
return {
|
||||
...state,
|
||||
activities: [
|
||||
...state.activities,
|
||||
...action.payload.global_activities.activities
|
||||
],
|
||||
more: action.payload.global_activities.more
|
||||
};
|
||||
const initialStateu = { more: true, activities: [] };
|
||||
|
||||
export function globalActivities(state = initialStateu, action) {
|
||||
switch (action.type) {
|
||||
case GLOBAL_ACTIVITIES_DATA:
|
||||
return {
|
||||
...state,
|
||||
activities: [
|
||||
...state.activities,
|
||||
...action.payload.global_activities.activities
|
||||
],
|
||||
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-size: 13px;
|
||||
}
|
||||
|
||||
.label-primary {
|
||||
background-color: $color-theme-primary;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"glob": "^7.1.2",
|
||||
"js-yaml": "^3.9.0",
|
||||
"lodash": "^4.17.4",
|
||||
"moment": "^2.18.1",
|
||||
"node-sass": "^4.5.3",
|
||||
"path-complete-extname": "^0.1.0",
|
||||
"postcss-loader": "^2.0.6",
|
||||
|
@ -65,6 +66,7 @@
|
|||
"react-dom": "^15.6.1",
|
||||
"react-intl": "^2.3.0",
|
||||
"react-intl-redux": "^0.6.0",
|
||||
"react-moment": "^0.6.4",
|
||||
"react-redux": "^5.0.5",
|
||||
"react-router-bootstrap": "^0.24.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:
|
||||
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:
|
||||
version "2.0.0"
|
||||
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"
|
||||
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:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.0.tgz#531898ff566c7e5c7226ead2863b8cf9fbb5a981"
|
||||
|
|
Loading…
Add table
Reference in a new issue