chore: Remove events log from settings
This commit is contained in:
@ -10,7 +10,6 @@ import {
|
|||||||
GroupIcon,
|
GroupIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
TeamIcon,
|
TeamIcon,
|
||||||
BulletedListIcon,
|
|
||||||
ExpandedIcon,
|
ExpandedIcon,
|
||||||
} from "outline-icons";
|
} from "outline-icons";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
@ -118,13 +117,6 @@ class SettingsSidebar extends React.Component<Props> {
|
|||||||
icon={<LinkIcon color="currentColor" />}
|
icon={<LinkIcon color="currentColor" />}
|
||||||
label="Share Links"
|
label="Share Links"
|
||||||
/>
|
/>
|
||||||
{can.auditLog && (
|
|
||||||
<SidebarLink
|
|
||||||
to="/settings/events"
|
|
||||||
icon={<BulletedListIcon color="currentColor" />}
|
|
||||||
label="Audit Log"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{can.export && (
|
{can.export && (
|
||||||
<SidebarLink
|
<SidebarLink
|
||||||
to="/settings/export"
|
to="/settings/export"
|
||||||
|
@ -3,7 +3,6 @@ import * as React from "react";
|
|||||||
import { Switch, Route } from "react-router-dom";
|
import { Switch, Route } from "react-router-dom";
|
||||||
import Settings from "scenes/Settings";
|
import Settings from "scenes/Settings";
|
||||||
import Details from "scenes/Settings/Details";
|
import Details from "scenes/Settings/Details";
|
||||||
import Events from "scenes/Settings/Events";
|
|
||||||
import Export from "scenes/Settings/Export";
|
import Export from "scenes/Settings/Export";
|
||||||
import Groups from "scenes/Settings/Groups";
|
import Groups from "scenes/Settings/Groups";
|
||||||
import Notifications from "scenes/Settings/Notifications";
|
import Notifications from "scenes/Settings/Notifications";
|
||||||
@ -25,7 +24,6 @@ export default function SettingsRoutes() {
|
|||||||
<Route exact path="/settings/groups" component={Groups} />
|
<Route exact path="/settings/groups" component={Groups} />
|
||||||
<Route exact path="/settings/shares" component={Shares} />
|
<Route exact path="/settings/shares" component={Shares} />
|
||||||
<Route exact path="/settings/tokens" component={Tokens} />
|
<Route exact path="/settings/tokens" component={Tokens} />
|
||||||
<Route exact path="/settings/events" component={Events} />
|
|
||||||
<Route exact path="/settings/notifications" component={Notifications} />
|
<Route exact path="/settings/notifications" component={Notifications} />
|
||||||
<Route exact path="/settings/integrations/slack" component={Slack} />
|
<Route exact path="/settings/integrations/slack" component={Slack} />
|
||||||
<Route exact path="/settings/integrations/zapier" component={Zapier} />
|
<Route exact path="/settings/integrations/zapier" component={Zapier} />
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { observable, action } from "mobx";
|
|
||||||
import { observer, inject } from "mobx-react";
|
|
||||||
import * as React from "react";
|
|
||||||
import { type Match } from "react-router-dom";
|
|
||||||
import { Waypoint } from "react-waypoint";
|
|
||||||
|
|
||||||
import { DEFAULT_PAGINATION_LIMIT } from "stores/BaseStore";
|
|
||||||
import EventsStore from "stores/EventsStore";
|
|
||||||
import CenteredContent from "components/CenteredContent";
|
|
||||||
import HelpText from "components/HelpText";
|
|
||||||
import List from "components/List";
|
|
||||||
import { ListPlaceholder } from "components/LoadingPlaceholder";
|
|
||||||
import PageTitle from "components/PageTitle";
|
|
||||||
import Tab from "components/Tab";
|
|
||||||
import Tabs from "components/Tabs";
|
|
||||||
import EventListItem from "./components/EventListItem";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
events: EventsStore,
|
|
||||||
match: Match,
|
|
||||||
};
|
|
||||||
|
|
||||||
@observer
|
|
||||||
class Events extends React.Component<Props> {
|
|
||||||
@observable isLoaded: boolean = false;
|
|
||||||
@observable isFetching: boolean = false;
|
|
||||||
@observable offset: number = 0;
|
|
||||||
@observable allowLoadMore: boolean = true;
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchResults();
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchResults = async () => {
|
|
||||||
this.isFetching = true;
|
|
||||||
|
|
||||||
const limit = DEFAULT_PAGINATION_LIMIT;
|
|
||||||
const results = await this.props.events.fetchPage({
|
|
||||||
limit,
|
|
||||||
offset: this.offset,
|
|
||||||
auditLog: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
|
||||||
results &&
|
|
||||||
(results.length === 0 || results.length < DEFAULT_PAGINATION_LIMIT)
|
|
||||||
) {
|
|
||||||
this.allowLoadMore = false;
|
|
||||||
} else {
|
|
||||||
this.offset += DEFAULT_PAGINATION_LIMIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isLoaded = true;
|
|
||||||
this.isFetching = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
@action
|
|
||||||
loadMoreResults = async () => {
|
|
||||||
// Don't paginate if there aren't more results or we’re in the middle of fetching
|
|
||||||
if (!this.allowLoadMore || this.isFetching) return;
|
|
||||||
await this.fetchResults();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { events } = this.props;
|
|
||||||
const showLoading = events.isFetching && !events.orderedData.length;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CenteredContent>
|
|
||||||
<PageTitle title="Audit Log" />
|
|
||||||
<h1>Audit Log</h1>
|
|
||||||
<HelpText>
|
|
||||||
The audit log details the history of security related and other events
|
|
||||||
across your knowledge base.
|
|
||||||
</HelpText>
|
|
||||||
|
|
||||||
<Tabs>
|
|
||||||
<Tab to="/settings/events" exact>
|
|
||||||
Events
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
<List>
|
|
||||||
{showLoading ? (
|
|
||||||
<ListPlaceholder count={5} />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{events.orderedData.map((event) => (
|
|
||||||
<EventListItem event={event} key={event.id} />
|
|
||||||
))}
|
|
||||||
{this.allowLoadMore && (
|
|
||||||
<Waypoint key={this.offset} onEnter={this.loadMoreResults} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
</CenteredContent>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default inject("events")(Events);
|
|
@ -1,232 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { capitalize } from "lodash";
|
|
||||||
import * as React from "react";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import Event from "models/Event";
|
|
||||||
import Avatar from "components/Avatar";
|
|
||||||
import ListItem from "components/List/Item";
|
|
||||||
import Time from "components/Time";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
event: Event,
|
|
||||||
};
|
|
||||||
|
|
||||||
const description = (event) => {
|
|
||||||
switch (event.name) {
|
|
||||||
case "api_keys.create":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Created the API token <strong>{event.data.name}</strong>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "api_keys.delete":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Revoked the API token <strong>{event.data.name}</strong>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "teams.create":
|
|
||||||
return "Created the team";
|
|
||||||
case "shares.create":
|
|
||||||
case "shares.revoke":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{capitalize(event.verbPastTense)} a{" "}
|
|
||||||
<Link to={`/share/${event.modelId || ""}`}>share link</Link> to the{" "}
|
|
||||||
<Link to={`/doc/${event.documentId}`}>{event.data.name}</Link>{" "}
|
|
||||||
document
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "shares.update":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{event.data.published ? (
|
|
||||||
<>
|
|
||||||
Published a document{" "}
|
|
||||||
<Link to={`/share/${event.modelId || ""}`}>share link</Link>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
Unpublished a document{" "}
|
|
||||||
<Link to={`/share/${event.modelId || ""}`}>share link</Link>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "users.create":
|
|
||||||
return <>{event.data.name} created an account</>;
|
|
||||||
case "users.invite":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{capitalize(event.verbPastTense)} {event.data.name} (
|
|
||||||
<a href={`mailto:${event.data.email || ""}`}>
|
|
||||||
{event.data.email || ""}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "users.suspend":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Suspended <strong>{event.data.name}’s</strong> account
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "users.activate":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Unsuspended <strong>{event.data.name}’s</strong> account
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "users.promote":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Made <strong>{event.data.name}</strong> an admin
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "users.demote":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Made <strong>{event.data.name}</strong> a member
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "users.delete":
|
|
||||||
return "Deleted their account";
|
|
||||||
case "groups.create":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Created the group <strong>{event.data.name}</strong>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "groups.update":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Update the group <strong>{event.data.name}</strong>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "groups.delete":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Deleted the group <strong>{event.data.name}</strong>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "collections.add_user":
|
|
||||||
case "collections.add_group":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Granted <strong>{event.data.name}</strong> access to a{" "}
|
|
||||||
<Link to={`/collections/${event.collectionId || ""}`}>
|
|
||||||
collection
|
|
||||||
</Link>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "collections.remove_user":
|
|
||||||
case "collections.remove_group":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Revoked <strong>{event.data.name}</strong> access to a{" "}
|
|
||||||
<Link to={`/collections/${event.collectionId || ""}`}>
|
|
||||||
collection
|
|
||||||
</Link>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.documentId) {
|
|
||||||
if (event.name === "documents.delete") {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Deleted the <strong>{event.data.title}</strong> document
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (event.name === "documents.create") {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{capitalize(event.verbPastTense)} the{" "}
|
|
||||||
<Link to={`/doc/${event.documentId}`}>
|
|
||||||
{event.data.title || "Untitled"}
|
|
||||||
</Link>{" "}
|
|
||||||
document{" "}
|
|
||||||
{event.data.templateId && (
|
|
||||||
<>
|
|
||||||
from a <Link to={`/doc/${event.data.templateId}`}>template</Link>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{capitalize(event.verbPastTense)} the{" "}
|
|
||||||
<Link to={`/doc/${event.documentId}`}>
|
|
||||||
{event.data.title || "Untitled"}
|
|
||||||
</Link>{" "}
|
|
||||||
document
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (event.collectionId) {
|
|
||||||
if (event.name === "collections.delete") {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
Deleted the <strong>{event.data.name}</strong> collection
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{capitalize(event.verbPastTense)} the{" "}
|
|
||||||
<Link to={`/collections/${event.collectionId || ""}`}>
|
|
||||||
{event.data.name}
|
|
||||||
</Link>{" "}
|
|
||||||
collection
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (event.userId) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{capitalize(event.verbPastTense)} the user {event.data.name}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
const EventListItem = ({ event }: Props) => {
|
|
||||||
return (
|
|
||||||
<ListItem
|
|
||||||
key={event.id}
|
|
||||||
title={event.actor.name}
|
|
||||||
image={<Avatar src={event.actor.avatarUrl} size={32} />}
|
|
||||||
subtitle={
|
|
||||||
<>
|
|
||||||
{description(event)} <Time dateTime={event.createdAt} /> ago ·{" "}
|
|
||||||
<strong>{event.name}</strong>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
actions={
|
|
||||||
event.actorIpAddress ? (
|
|
||||||
<IP>
|
|
||||||
<a
|
|
||||||
href={`http://geoiplookup.net/ip/${event.actorIpAddress}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
>
|
|
||||||
{event.actorIpAddress}
|
|
||||||
</a>
|
|
||||||
</IP>
|
|
||||||
) : undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const IP = styled("span")`
|
|
||||||
color: ${(props) => props.theme.textTertiary};
|
|
||||||
font-size: 12px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default EventListItem;
|
|
@ -1,19 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { sortBy } from "lodash";
|
|
||||||
import { computed } from "mobx";
|
|
||||||
import Event from "models/Event";
|
|
||||||
import BaseStore from "./BaseStore";
|
|
||||||
import RootStore from "./RootStore";
|
|
||||||
|
|
||||||
export default class EventsStore extends BaseStore<Event> {
|
|
||||||
actions = ["list"];
|
|
||||||
|
|
||||||
constructor(rootStore: RootStore) {
|
|
||||||
super(rootStore, Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed
|
|
||||||
get orderedData(): Event[] {
|
|
||||||
return sortBy(Array.from(this.data.values()), "createdAt").reverse();
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,6 @@ import CollectionGroupMembershipsStore from "./CollectionGroupMembershipsStore";
|
|||||||
import CollectionsStore from "./CollectionsStore";
|
import CollectionsStore from "./CollectionsStore";
|
||||||
import DocumentPresenceStore from "./DocumentPresenceStore";
|
import DocumentPresenceStore from "./DocumentPresenceStore";
|
||||||
import DocumentsStore from "./DocumentsStore";
|
import DocumentsStore from "./DocumentsStore";
|
||||||
import EventsStore from "./EventsStore";
|
|
||||||
import GroupMembershipsStore from "./GroupMembershipsStore";
|
import GroupMembershipsStore from "./GroupMembershipsStore";
|
||||||
import GroupsStore from "./GroupsStore";
|
import GroupsStore from "./GroupsStore";
|
||||||
import IntegrationsStore from "./IntegrationsStore";
|
import IntegrationsStore from "./IntegrationsStore";
|
||||||
@ -24,7 +23,6 @@ export default class RootStore {
|
|||||||
collections: CollectionsStore;
|
collections: CollectionsStore;
|
||||||
collectionGroupMemberships: CollectionGroupMembershipsStore;
|
collectionGroupMemberships: CollectionGroupMembershipsStore;
|
||||||
documents: DocumentsStore;
|
documents: DocumentsStore;
|
||||||
events: EventsStore;
|
|
||||||
groups: GroupsStore;
|
groups: GroupsStore;
|
||||||
groupMemberships: GroupMembershipsStore;
|
groupMemberships: GroupMembershipsStore;
|
||||||
integrations: IntegrationsStore;
|
integrations: IntegrationsStore;
|
||||||
@ -44,7 +42,6 @@ export default class RootStore {
|
|||||||
this.collections = new CollectionsStore(this);
|
this.collections = new CollectionsStore(this);
|
||||||
this.collectionGroupMemberships = new CollectionGroupMembershipsStore(this);
|
this.collectionGroupMemberships = new CollectionGroupMembershipsStore(this);
|
||||||
this.documents = new DocumentsStore(this);
|
this.documents = new DocumentsStore(this);
|
||||||
this.events = new EventsStore(this);
|
|
||||||
this.groups = new GroupsStore(this);
|
this.groups = new GroupsStore(this);
|
||||||
this.groupMemberships = new GroupMembershipsStore(this);
|
this.groupMemberships = new GroupMembershipsStore(this);
|
||||||
this.integrations = new IntegrationsStore(this);
|
this.integrations = new IntegrationsStore(this);
|
||||||
@ -65,7 +62,6 @@ export default class RootStore {
|
|||||||
this.collections.clear();
|
this.collections.clear();
|
||||||
this.collectionGroupMemberships.clear();
|
this.collectionGroupMemberships.clear();
|
||||||
this.documents.clear();
|
this.documents.clear();
|
||||||
this.events.clear();
|
|
||||||
this.groups.clear();
|
this.groups.clear();
|
||||||
this.groupMemberships.clear();
|
this.groupMemberships.clear();
|
||||||
this.integrations.clear();
|
this.integrations.clear();
|
||||||
|
Reference in New Issue
Block a user