Skip to content
Snippets Groups Projects
Commit 80461ff0 authored by Tom Robinson's avatar Tom Robinson
Browse files

Remove old pulse listing

parent 5c8b3d28
No related branches found
No related tags found
No related merge requests found
......@@ -22,9 +22,11 @@ export default class SearchApp extends React.Component {
const { location } = this.props;
return (
<Box mx={PAGE_PADDING}>
<Flex align="center" mb={2} py={[2, 3]}>
<Subhead>{jt`Results for "${location.query.q}"`}</Subhead>
</Flex>
{location.query.q && (
<Flex align="center" mb={2} py={[2, 3]}>
<Subhead>{jt`Results for "${location.query.q}"`}</Subhead>
</Flex>
)}
<ItemTypeFilterBar
analyticsContext={`Search Results`}
filters={FILTERS.concat({
......
import React, { Component } from "react";
import { t } from "c-3po";
import PulseListItem from "./PulseListItem.jsx";
import WhatsAPulse from "./WhatsAPulse.jsx";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper.jsx";
import ChannelSetupModal from "metabase/components/ChannelSetupModal";
import Modal from "metabase/components/Modal.jsx";
import _ from "underscore";
export default class PulseList extends Component {
constructor(props, context) {
super(props, context);
this.state = {
showSetupModal: false,
};
_.bindAll(this, "create");
}
static propTypes = {};
static defaultProps = {};
componentDidMount() {
this.props.fetchPulses();
this.props.fetchPulseFormInput();
}
create() {
if (this.props.hasConfiguredAnyChannel) {
this.props.onChangeLocation("/pulse/create");
} else {
this.setState({ showSetupModal: true });
}
}
render() {
let { pulses, user } = this.props;
return (
<div className="PulseList px3">
<div className="border-bottom mb2 mt3">
<div className="wrapper wrapper--trim flex align-center mb2">
<h1>{t`Pulses`}</h1>
<a
onClick={this.create}
className="PulseButton Button flex-align-right"
>{t`Create a pulse`}</a>
</div>
</div>
<LoadingAndErrorWrapper loading={!pulses}>
{() =>
pulses.length > 0 ? (
<ul className="wrapper wrapper--trim">
{pulses
.slice()
.sort((a, b) => b.created_at - a.created_at)
.map(pulse => (
<li key={pulse.id}>
<PulseListItem
scrollTo={pulse.id === this.props.pulseId}
pulse={pulse}
user={user}
formInput={this.props.formInput}
savePulse={this.props.savePulse}
/>
</li>
))}
</ul>
) : (
<div className="mt4 ml-auto mr-auto">
<WhatsAPulse
button={
<a
onClick={this.create}
className="Button Button--primary"
>{t`Create a pulse`}</a>
}
/>
</div>
)
}
</LoadingAndErrorWrapper>
<Modal isOpen={this.state.showSetupModal}>
<ChannelSetupModal
user={user}
onClose={() => this.setState({ showSetupModal: false })}
onChangeLocation={this.props.onChangeLocation}
entityNamePlural={t`pulses`}
/>
</Modal>
</div>
);
}
}
/* eslint "react/prop-types": "warn" */
import React, { Component } from "react";
import PropTypes from "prop-types";
import { t, ngettext, msgid } from "c-3po";
import Icon from "metabase/components/Icon.jsx";
import _ from "underscore";
export default class PulseListChannel extends Component {
constructor(props, context) {
super(props, context);
_.bindAll(this, "subscribe", "unsubscribe");
}
static propTypes = {
pulse: PropTypes.object.isRequired,
channel: PropTypes.object.isRequired,
channelSpec: PropTypes.object,
user: PropTypes.object.isRequired,
savePulse: PropTypes.func.isRequired,
};
subscribe() {
let { pulse, channel, user } = this.props;
this.props.savePulse({
...pulse,
channels: pulse.channels.map(
c =>
c !== channel ? c : { ...c, recipients: [...c.recipients, user] },
),
});
}
unsubscribe() {
let { pulse, channel, user } = this.props;
this.props.savePulse({
...pulse,
channels: pulse.channels.map(
c =>
c !== channel
? c
: { ...c, recipients: c.recipients.filter(r => r.id !== user.id) },
),
});
}
renderChannelSchedule() {
let { channel, channelSpec } = this.props;
let channelIcon = null;
let channelVerb =
(channelSpec && channelSpec.displayName) || channel.channel_type;
let channelSchedule = channel.schedule_type;
let channelTarget =
channel.recipients &&
(n => ngettext(msgid`${n} person`, `${n} people`, n))(
channel.recipients.length,
);
if (channel.channel_type === "email") {
channelIcon = "mail";
channelVerb = t`Emailed`;
} else if (channel.channel_type === "slack") {
channelIcon = "slack";
channelVerb = t`Slack'd`;
// Address #5799 where `details` object is missing for some reason
channelTarget = channel.details ? channel.details.channel : t`No channel`;
}
return (
<div className="h4 text-medium py2 flex align-center">
{channelIcon && <Icon className="mr1" name={channelIcon} size={24} />}
<span>
{channelVerb + " "}
<strong>{channelSchedule}</strong>
{channelTarget && (
<span>
{" " + t`to` + " "}
<strong>{channelTarget}</strong>
</span>
)}
</span>
</div>
);
}
render() {
let { pulse, channel, channelSpec, user } = this.props;
let subscribable = channelSpec && channelSpec.allows_recipients;
let subscribed = false;
if (subscribable) {
subscribed = _.any(channel.recipients, r => r.id === user.id);
}
return (
<div className="py2 flex align-center">
{this.renderChannelSchedule()}
{subscribable && (
<div className="flex-align-right">
{subscribed ? (
<div className="flex align-center rounded bg-green text-white text-bold">
<div className="pl2">{t`You get this ${
channel.channel_type
}`}</div>
<Icon
className="p2 text-light text-white-hover cursor-pointer"
name="close"
size={12}
onClick={this.unsubscribe}
/>
</div>
) : !pulse.read_only ? (
<div
className="flex align-center rounded bordered bg-white text-default text-bold cursor-pointer"
onClick={this.subscribe}
>
<Icon className="p2" name="add" size={12} />
<div className="pr2">{t`Get this ${channel.channel_type}`}</div>
</div>
) : null}
</div>
)}
</div>
);
}
}
/* eslint "react/prop-types": "warn" */
import React, { Component } from "react";
import PropTypes from "prop-types";
import ReactDOM from "react-dom";
import { Link } from "react-router";
import { jt, t } from "c-3po";
import cx from "classnames";
import * as Urls from "metabase/lib/urls";
import PulseListChannel from "./PulseListChannel.jsx";
export default class PulseListItem extends Component {
static propTypes = {
pulse: PropTypes.object.isRequired,
formInput: PropTypes.object.isRequired,
user: PropTypes.object.isRequired,
scrollTo: PropTypes.bool.isRequired,
savePulse: PropTypes.func.isRequired,
};
componentDidMount() {
if (this.props.scrollTo) {
const element = ReactDOM.findDOMNode(this.refs.pulseListItem);
element.scrollIntoView(true);
}
}
render() {
let { pulse, formInput, user } = this.props;
const creator = (
<span className="text-bold">
{pulse.creator && pulse.creator.common_name}
</span>
);
return (
<div
ref="pulseListItem"
className={cx("PulseListItem bordered rounded mb2 pt3", {
"PulseListItem--focused": this.props.scrollTo,
})}
>
<div className="px4 mb2">
<div className="flex align-center mb1">
<h2 className="break-word" style={{ maxWidth: "80%" }}>
{pulse.name}
</h2>
{!pulse.read_only && (
<div className="ml-auto">
<Link
to={"/pulse/" + pulse.id}
className="PulseEditButton PulseButton Button no-decoration text-bold"
>
{t`Edit`}
</Link>
</div>
)}
</div>
<span>{jt`Pulse by ${creator}`}</span>
</div>
<ol className="mb2 px4 flex flex-wrap">
{pulse.cards.map((card, index) => (
<li key={index} className="mr1 mb1">
<Link to={Urls.question(card.id)} className="Button">
{card.name}
</Link>
</li>
))}
</ol>
<ul className="border-top px4 bg-light">
{pulse.channels.filter(channel => channel.enabled).map(channel => (
<li key={channel.id} className="border-row-divider">
<PulseListChannel
pulse={pulse}
channel={channel}
channelSpec={
formInput.channels && formInput.channels[channel.channel_type]
}
user={user}
savePulse={this.props.savePulse}
/>
</li>
))}
</ul>
</div>
);
}
}
/* eslint "react/prop-types": "warn" */
import React, { Component } from "react";
import { connect } from "react-redux";
import { push } from "react-router-redux";
import PulseList from "../components/PulseList.jsx";
import { listPulseSelectors } from "../selectors";
import { fetchPulses, fetchPulseFormInput, savePulse } from "../actions";
const mapStateToProps = (state, props) => {
return {
...listPulseSelectors(state, props),
user: state.currentUser,
// onChangeLocation: onChangeLocation
};
};
const mapDispatchToProps = {
fetchPulses,
fetchPulseFormInput,
savePulse,
onChangeLocation: push,
};
@connect(mapStateToProps, mapDispatchToProps)
export default class PulseListApp extends Component {
render() {
return <PulseList {...this.props} />;
}
}
......@@ -44,7 +44,6 @@ import CollectionPermissionsModal from "metabase/admin/permissions/containers/Co
import UserCollectionList from "metabase/containers/UserCollectionList";
import PulseEditApp from "metabase/pulse/containers/PulseEditApp.jsx";
import PulseListApp from "metabase/pulse/containers/PulseListApp.jsx";
import PulseMoveModal from "metabase/pulse/components/PulseMoveModal";
import SetupApp from "metabase/setup/containers/SetupApp.jsx";
import PostSetupApp from "metabase/setup/containers/PostSetupApp.jsx";
......@@ -321,7 +320,8 @@ export const getRoutes = store => (
{/* PULSE */}
<Route path="/pulse" title={t`Pulses`}>
<IndexRoute component={PulseListApp} />
{/* NOTE: legacy route, not linked to in app */}
<IndexRedirect to="/search" query={{ type: "pulse" }} />
<Route path="create" component={PulseEditApp} />
<Route path=":pulseId">
<IndexRoute component={PulseEditApp} />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment