Turn on all of Microsoft's recommend lint rules

Biggest changes forced by this: alt tags for all images, resulting in
new strings added to messages.json, and a new i18n paramter/prop added
in a plot of places.

Another change of note is that there are two new tslint.json files under
ts/test and ts/styleguide to relax our rules a bit there. This required
a change to our package.json script, as manually specifying the config
file there made it ignore our tslint.json files in subdirectories
This commit is contained in:
Scott Nonnenberg 2018-05-22 12:31:43 -07:00
parent 23586be6b0
commit 2988da0981
49 changed files with 311 additions and 123 deletions

View file

@ -20,5 +20,10 @@ const messages = [
},
];
<AttachmentSection header="Today" type="documents" messages={messages} />;
<AttachmentSection
header="Today"
type="documents"
messages={messages}
i18n={util.i18n}
/>;
```

View file

@ -33,7 +33,7 @@ interface Props {
onItemClick?: (event: ItemClickEvent) => void;
}
export class AttachmentSection extends React.Component<Props, {}> {
export class AttachmentSection extends React.Component<Props> {
public render() {
const { header } = this.props;

View file

@ -4,17 +4,20 @@
fileName="meow.jpg"
fileSize={1024 * 1000 * 2}
timestamp={Date.now()}
i18n={util.i18n}
/>
<DocumentListItem
fileName="rickroll.wmv"
fileSize={1024 * 1000 * 8}
timestamp={Date.now() - 24 * 60 * 1000}
i18n={util.i18n}
/>
<DocumentListItem
fileName="kitten.gif"
fileSize={1024 * 1000 * 1.2}
timestamp={Date.now() - 14 * 24 * 60 * 1000}
shouldShowSeparator={false}
i18n={util.i18n}
/>
</div>
```

View file

@ -1,11 +1,14 @@
import React from 'react';
import moment from 'moment';
// tslint:disable-next-line:match-default-export-name
import formatFileSize from 'filesize';
import { Localizer } from '../../../types/Util';
interface Props {
// Required
i18n: (key: string, values?: Array<string>) => string;
i18n: Localizer;
timestamp: number;
// Optional
@ -58,13 +61,14 @@ const styles = {
},
};
export class DocumentListItem extends React.Component<Props, {}> {
export class DocumentListItem extends React.Component<Props> {
public static defaultProps: Partial<Props> = {
shouldShowSeparator: true,
};
public render() {
const { shouldShowSeparator } = this.props;
return (
<div
style={{
@ -78,11 +82,16 @@ export class DocumentListItem extends React.Component<Props, {}> {
}
private renderContent() {
const { fileName, fileSize, timestamp } = this.props;
const { fileName, fileSize, timestamp, i18n } = this.props;
return (
<div style={styles.itemContainer} onClick={this.props.onClick}>
<div
style={styles.itemContainer}
role="button"
onClick={this.props.onClick}
>
<img
alt={i18n('fileIconAlt')}
src="images/file.svg"
width="48"
height="48"

View file

@ -21,9 +21,10 @@ const styles = {
} as React.CSSProperties,
};
export class EmptyState extends React.Component<Props, {}> {
export class EmptyState extends React.Component<Props> {
public render() {
const { label } = this.props;
return <div style={styles.container}>{label}</div>;
}
}

View file

@ -6,6 +6,7 @@
i18n={window.i18n}
media={[]}
documents={[]}
i18n={util.i18n}
/>
</div>
```
@ -72,7 +73,7 @@ const messages = _.sortBy(
message => -message.received_at
);
<MediaGallery i18n={window.i18n} media={messages} documents={messages} />;
<MediaGallery i18n={util.i18n} media={messages} documents={messages} />;
```
## Media gallery with one document
@ -83,5 +84,5 @@ const messages = [
attachments: [{ fileName: 'foo.jpg', contentType: 'application/json' }],
},
];
<MediaGallery i18n={window.i18n} media={messages} documents={messages} />;
<MediaGallery i18n={util.i18n} media={messages} documents={messages} />;
```

View file

@ -81,12 +81,17 @@ const Tab = ({
onSelect?: (event: TabSelectEvent) => void;
type: AttachmentType;
}) => {
const handleClick = onSelect ? () => onSelect({ type }) : undefined;
const handleClick = onSelect
? () => {
onSelect({ type });
}
: undefined;
return (
<div
style={isSelected ? styles.tab.active : styles.tab.default}
onClick={handleClick}
role="tab"
>
{label}
</div>
@ -146,6 +151,7 @@ export class MediaGallery extends React.Component<Props, State> {
throw missingCaseError(type);
}
})();
return <EmptyState data-test="EmptyState" label={label} />;
}
@ -157,6 +163,7 @@ export class MediaGallery extends React.Component<Props, State> {
section.type === 'yearMonth'
? date.format(MONTH_FORMAT)
: i18n(section.type);
return (
<AttachmentSection
key={header}

View file

@ -25,7 +25,7 @@ const styles = {
},
};
export class MediaGridItem extends React.Component<Props, {}> {
export class MediaGridItem extends React.Component<Props> {
public renderContent() {
const { message } = this.props;
@ -46,7 +46,7 @@ export class MediaGridItem extends React.Component<Props, {}> {
public render() {
return (
<div style={styles.container} onClick={this.props.onClick}>
<div style={styles.container} role="button" onClick={this.props.onClick}>
{this.renderContent()}
</div>
);

View file

@ -31,6 +31,7 @@ export const groupMessagesByDate = (
const yearMonthMessages = Object.values(
groupBy(groupedMessages.yearMonth, 'order')
).reverse();
return compact([
toSection(groupedMessages.today),
toSection(groupedMessages.yesterday),
@ -138,6 +139,7 @@ const withSection = (referenceDateTime: moment.Moment) => (
const month: number = messageReceivedDate.month();
const year: number = messageReceivedDate.year();
return {
order: year * 100 + month,
type: 'yearMonth',

View file

@ -66,6 +66,7 @@ export const withObjectURL = (message: Message): Message => {
data: attachment.data,
type: attachment.contentType,
});
return {
...message,
objectURL,