add markdown option to logs page

pull/1440/head
gabrielburnworth 2019-09-16 14:22:20 -07:00
parent d2ae4ff300
commit c7c2a57749
7 changed files with 56 additions and 6 deletions

View File

@ -991,6 +991,14 @@ ul {
@media screen and (max-width: 974px) {
padding-left: 0 !important;
}
.fa-2x {
float: right;
font-size: 1rem;
color: $dark_gray;
}
.fa-ban {
color: $medium_gray;
}
}
.logs-settings-menu {
@ -1024,6 +1032,18 @@ ul {
box-shadow: inset 1px 0 0 0 $gray !important;
color: $dark_gray !important;
word-break: break-word;
.markdown {
p {
display: block;
color: $dark_gray;
font: inherit;
font-size: inherit;
text-overflow: inherit;
overflow: inherit;
width: inherit;
white-space: inherit;
}
}
}
td:nth-child(1),
td:nth-child(4) {

View File

@ -156,4 +156,21 @@ describe("<Logs />", () => {
wrapper.instance().setFilterLevel(MessageType.warn)(2);
expect(wrapper.instance().state.warn).toEqual(2);
});
it("toggles raw text display", () => {
const wrapper = mount<Logs>(<Logs {...fakeProps()} />);
expect(wrapper.state().markdown).toBeFalsy();
wrapper.find(".fa-stack").simulate("click");
expect(wrapper.state().markdown).toBeTruthy();
});
it("renders formatted messages", () => {
const p = fakeProps();
p.logs[0].body.message = "`message`";
const wrapper = mount<Logs>(<Logs {...p} />);
expect(wrapper.state().markdown).toBeFalsy();
expect(wrapper.html()).not.toContain("<code>message</code>");
wrapper.setState({ markdown: true });
expect(wrapper.html()).toContain("<code>message</code>");
});
});

View File

@ -9,7 +9,7 @@ const logTypes = MESSAGE_TYPES;
describe("<LogsFilterMenu />", () => {
const fakeState: LogsState = {
autoscroll: true, success: 1, busy: 1, warn: 1,
autoscroll: true, markdown: false, success: 1, busy: 1, warn: 1,
error: 1, info: 1, fun: 1, debug: 1, assertion: 1,
};
@ -24,7 +24,8 @@ describe("<LogsFilterMenu />", () => {
const wrapper = mount(<LogsFilterMenu {...fakeProps()} />);
logTypes.filter(x => x !== "assertion").map(string =>
expect(wrapper.text().toLowerCase()).toContain(string.toLowerCase()));
expect(wrapper.text().toLowerCase()).not.toContain("autoscroll");
["autoscroll", "markdown"].map(string =>
expect(wrapper.text().toLowerCase()).not.toContain(string));
});
it("renders new types", () => {
@ -33,7 +34,8 @@ describe("<LogsFilterMenu />", () => {
const wrapper = mount(<LogsFilterMenu {...p} />);
logTypes.map(string =>
expect(wrapper.text().toLowerCase()).toContain(string.toLowerCase()));
expect(wrapper.text().toLowerCase()).not.toContain("autoscroll");
["autoscroll", "markdown"].map(string =>
expect(wrapper.text().toLowerCase()).not.toContain(string));
});
it("filters logs", () => {

View File

@ -28,7 +28,7 @@ const menuSort = (a: string, b: string) =>
export const filterStateKeys =
(state: LogsState, shouldDisplay: ShouldDisplay) =>
Object.keys(state)
.filter(key => key !== "autoscroll")
.filter(key => !["autoscroll", "markdown"].includes(key))
.filter(key => shouldDisplay(Feature.assertion_block)
|| key !== "assertion");

View File

@ -7,10 +7,12 @@ import { isNumber, startCase } from "lodash";
import { t } from "../../i18next_wrapper";
import { TimeSettings } from "../../interfaces";
import { UUID } from "../../resources/interfaces";
import { Markdown } from "../../ui";
interface LogsRowProps {
tlog: TaggedLog;
dispatch: Function;
markdown: boolean;
timeSettings: TimeSettings;
}
@ -37,7 +39,7 @@ const LogVerbositySaucer = (props: LogVerbositySaucerProps) =>
</div>;
/** A log is displayed in a single row of the logs table. */
const LogsRow = ({ tlog, timeSettings, dispatch }: LogsRowProps) => {
const LogsRow = ({ tlog, timeSettings, dispatch, markdown }: LogsRowProps) => {
const { uuid } = tlog;
const { x, y, z, verbosity, type, created_at, message, id } = tlog.body;
const time = formatLogTime(created_at || NaN, timeSettings);
@ -48,7 +50,7 @@ const LogsRow = ({ tlog, timeSettings, dispatch }: LogsRowProps) => {
{t(startCase(type))}
</td>
<td>
{message || t("Loading")}
{markdown ? <Markdown>{message}</Markdown> : message || t("Loading")}
</td>
<td>
{xyzTableEntry(x, y, z)}
@ -83,6 +85,7 @@ export const LogsTable = (props: LogsTableProps) => {
key={log.uuid}
tlog={log}
dispatch={props.dispatch}
markdown={props.state.markdown}
timeSettings={props.timeSettings} />)}
</tbody>
</table>;

View File

@ -50,6 +50,7 @@ export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
fun: this.initialize(NumericSetting.fun_log, 1),
debug: this.initialize(NumericSetting.debug_log, 1),
assertion: this.initialize(NumericSetting.assertion_log, 1),
markdown: false,
};
/** Toggle display of a log type. Verbosity level 0 hides all, 3 shows all.*/
@ -113,6 +114,12 @@ export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
setFilterLevel={this.setFilterLevel} />
</Popover>
</div>
<div className="fa-stack fa-2x"
title={this.state.markdown ? t("display raw") : t("display markdown")}
onClick={() => this.setState({ markdown: !this.state.markdown })}>
<i className="fa fa-font fa-stack-1x" />
{this.state.markdown && <i className="fa fa-ban fa-stack-2x" />}
</div>
</Col>
</Row>
<Row>

View File

@ -16,6 +16,7 @@ export type Filters = Record<ALLOWED_MESSAGE_TYPES, number>;
export interface LogsState extends Filters {
autoscroll: boolean;
markdown: boolean;
}
export interface LogsTableProps {