forked from Archives/Athou_commafeed
use stricter eslint rules
This commit is contained in:
@@ -1,28 +1,36 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
es2021: true
|
es2021: true,
|
||||||
},
|
},
|
||||||
extends: ["standard-with-typescript", "plugin:react/recommended", "plugin:react-hooks/recommended", "plugin:prettier/recommended"],
|
extends: [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/strict-type-checked",
|
||||||
|
"plugin:@typescript-eslint/stylistic-type-checked",
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"plugin:react-hooks/recommended",
|
||||||
|
"plugin:prettier/recommended",
|
||||||
|
],
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
version: "detect"
|
version: "detect",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
env: {
|
env: {
|
||||||
node: true
|
node: true,
|
||||||
},
|
},
|
||||||
files: [".eslintrc.{js,cjs}"],
|
files: [".eslintrc.{js,cjs}"],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: "script"
|
sourceType: "script",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
|
project: true,
|
||||||
ecmaVersion: "latest",
|
ecmaVersion: "latest",
|
||||||
sourceType: "module"
|
sourceType: "module",
|
||||||
},
|
},
|
||||||
plugins: ["react"],
|
plugins: ["react"],
|
||||||
rules: {
|
rules: {
|
||||||
@@ -31,11 +39,13 @@ module.exports = {
|
|||||||
"@typescript-eslint/no-confusing-void-expression": ["error", { ignoreArrowShorthand: true }],
|
"@typescript-eslint/no-confusing-void-expression": ["error", { ignoreArrowShorthand: true }],
|
||||||
"@typescript-eslint/no-floating-promises": "off",
|
"@typescript-eslint/no-floating-promises": "off",
|
||||||
"@typescript-eslint/no-misused-promises": "off",
|
"@typescript-eslint/no-misused-promises": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||||
"@typescript-eslint/prefer-nullish-coalescing": ["error", { ignoreConditionalTests: true }],
|
"@typescript-eslint/prefer-nullish-coalescing": ["error", { ignoreConditionalTests: true }],
|
||||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||||
"@typescript-eslint/unbound-method": "off",
|
"@typescript-eslint/unbound-method": "off",
|
||||||
"react/no-unescaped-entities": "off",
|
"react/no-unescaped-entities": "off",
|
||||||
"react/react-in-jsx-scope": "off",
|
"react/react-in-jsx-scope": "off",
|
||||||
"react-hooks/exhaustive-deps": "error"
|
"react-hooks/exhaustive-deps": "error",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
844
commafeed-client/package-lock.json
generated
844
commafeed-client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -61,12 +61,11 @@
|
|||||||
"@types/swagger-ui-react": "^4.18.3",
|
"@types/swagger-ui-react": "^4.18.3",
|
||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@types/tinycon": "^0.6.5",
|
"@types/tinycon": "^0.6.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-config-standard-with-typescript": "^43.0.1",
|
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ const axiosInstance = axios.create({ baseURL: "./rest", withCredentials: true })
|
|||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
response => response,
|
response => response,
|
||||||
error => {
|
error => {
|
||||||
const { status, data } = error.response
|
if (axios.isAxiosError(error) && error.response) {
|
||||||
if (
|
const { status, data } = error.response
|
||||||
(status === 401 && data?.message === "Credentials are required to access this resource.") ||
|
if (
|
||||||
(status === 403 && data?.message === "You don't have the required role to access this resource.")
|
(status === 401 && data?.message === "Credentials are required to access this resource.") ||
|
||||||
) {
|
(status === 403 && data?.message === "You don't have the required role to access this resource.")
|
||||||
window.location.hash = data?.allowRegistrations ? "/welcome" : "/login"
|
) {
|
||||||
|
window.location.hash = data?.allowRegistrations ? "/welcome" : "/login"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
@@ -107,13 +109,11 @@ export const client = {
|
|||||||
export const errorToStrings = (err: unknown) => {
|
export const errorToStrings = (err: unknown) => {
|
||||||
let strings: string[] = []
|
let strings: string[] = []
|
||||||
|
|
||||||
if (axios.isAxiosError(err)) {
|
if (axios.isAxiosError(err) && err.response) {
|
||||||
if (err.response) {
|
const { data } = err.response
|
||||||
const { data } = err.response
|
if (typeof data === "string") strings.push(data)
|
||||||
if (typeof data === "string") strings.push(data)
|
if (typeof data === "object" && data.message) strings.push(data.message as string)
|
||||||
if (typeof data === "object" && data.message) strings.push(data.message as string)
|
if (typeof data === "object" && data.errors) strings = [...strings, ...data.errors]
|
||||||
if (typeof data === "object" && data.errors) strings = [...strings, ...data.errors]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings
|
return strings
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable import/first */
|
|
||||||
import { configureStore } from "@reduxjs/toolkit"
|
import { configureStore } from "@reduxjs/toolkit"
|
||||||
import { type client } from "app/client"
|
import { type client } from "app/client"
|
||||||
import { loadEntries, loadMoreEntries, markAllEntries, markEntry } from "app/entries/thunks"
|
import { loadEntries, loadMoreEntries, markAllEntries, markEntry } from "app/entries/thunks"
|
||||||
@@ -90,7 +89,7 @@ describe("entries", () => {
|
|||||||
expect(store.getState().entries.hasMore).toBe(false)
|
expect(store.getState().entries.hasMore).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("marks an entry as read", async () => {
|
it("marks an entry as read", () => {
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: reducers,
|
reducer: reducers,
|
||||||
preloadedState: {
|
preloadedState: {
|
||||||
@@ -117,7 +116,7 @@ describe("entries", () => {
|
|||||||
expect(mockClient.entry.mark).toHaveBeenCalledWith({ id: "3", read: true })
|
expect(mockClient.entry.mark).toHaveBeenCalledWith({ id: "3", read: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it("marks all entries as read", async () => {
|
it("marks all entries as read", () => {
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: reducers,
|
reducer: reducers,
|
||||||
preloadedState: {
|
preloadedState: {
|
||||||
|
|||||||
@@ -46,11 +46,11 @@ const buildGetEntriesPaginatedRequest = (state: RootState, source: EntrySource,
|
|||||||
tag: source.type === "tag" ? source.id : undefined,
|
tag: source.type === "tag" ? source.id : undefined,
|
||||||
keywords: state.entries.search,
|
keywords: state.entries.search,
|
||||||
})
|
})
|
||||||
export const reloadEntries = createAppAsyncThunk("entries/reload", async (arg, thunkApi) => {
|
export const reloadEntries = createAppAsyncThunk("entries/reload", (arg, thunkApi) => {
|
||||||
const state = thunkApi.getState()
|
const state = thunkApi.getState()
|
||||||
thunkApi.dispatch(loadEntries({ source: state.entries.source, clearSearch: false }))
|
thunkApi.dispatch(loadEntries({ source: state.entries.source, clearSearch: false }))
|
||||||
})
|
})
|
||||||
export const search = createAppAsyncThunk("entries/search", async (arg: string, thunkApi) => {
|
export const search = createAppAsyncThunk("entries/search", (arg: string, thunkApi) => {
|
||||||
const state = thunkApi.getState()
|
const state = thunkApi.getState()
|
||||||
thunkApi.dispatch(setSearch(arg))
|
thunkApi.dispatch(setSearch(arg))
|
||||||
thunkApi.dispatch(loadEntries({ source: state.entries.source, clearSearch: false }))
|
thunkApi.dispatch(loadEntries({ source: state.entries.source, clearSearch: false }))
|
||||||
@@ -84,7 +84,7 @@ export const markMultipleEntries = createAppAsyncThunk(
|
|||||||
thunkApi.dispatch(reloadTree())
|
thunkApi.dispatch(reloadTree())
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
export const markEntriesUpToEntry = createAppAsyncThunk("entries/entry/upToEntry", async (arg: Entry, thunkApi) => {
|
export const markEntriesUpToEntry = createAppAsyncThunk("entries/entry/upToEntry", (arg: Entry, thunkApi) => {
|
||||||
const state = thunkApi.getState()
|
const state = thunkApi.getState()
|
||||||
const { entries } = state.entries
|
const { entries } = state.entries
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class HighlightMatcher extends Matcher {
|
|||||||
return this.doMatch(string, new RegExp(pattern, "i"), () => ({}))
|
return this.doMatch(string, new RegExp(pattern, "i"), () => ({}))
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceWith(children: ChildrenNode, props: unknown): Node {
|
replaceWith(children: ChildrenNode): Node {
|
||||||
return <Mark>{children}</Mark>
|
return <Mark>{children}</Mark>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { BasicHtmlStyles } from "components/content/BasicHtmlStyles"
|
|||||||
import { ImageWithPlaceholderWhileLoading } from "components/ImageWithPlaceholderWhileLoading"
|
import { ImageWithPlaceholderWhileLoading } from "components/ImageWithPlaceholderWhileLoading"
|
||||||
|
|
||||||
export function Enclosure(props: { enclosureType: string; enclosureUrl: string }) {
|
export function Enclosure(props: { enclosureType: string; enclosureUrl: string }) {
|
||||||
const hasVideo = props.enclosureType?.startsWith("video")
|
const hasVideo = props.enclosureType.startsWith("video")
|
||||||
const hasAudio = props.enclosureType?.startsWith("audio")
|
const hasAudio = props.enclosureType.startsWith("audio")
|
||||||
const hasImage = props.enclosureType?.startsWith("image")
|
const hasImage = props.enclosureType.startsWith("image")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BasicHtmlStyles>
|
<BasicHtmlStyles>
|
||||||
|
|||||||
@@ -295,7 +295,6 @@ export function FeedEntries() {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!entries) return <Loader />
|
|
||||||
return (
|
return (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
id="entries"
|
id="entries"
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function ShareButtons(props: { url: string; description: string }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleGrid cols={4}>
|
<SimpleGrid cols={4}>
|
||||||
{(Object.keys(Constants.sharing) as Array<keyof SharingSettings>)
|
{(Object.keys(Constants.sharing) as (keyof SharingSettings)[])
|
||||||
.filter(site => sharingSettings?.[site])
|
.filter(site => sharingSettings?.[site])
|
||||||
.map(site => (
|
.map(site => (
|
||||||
<ShareButton
|
<ShareButton
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function ImportOpml() {
|
|||||||
|
|
||||||
const form = useForm<{ file: File }>({
|
const form = useForm<{ file: File }>({
|
||||||
validate: {
|
validate: {
|
||||||
file: v => (v ? null : t`file is required`),
|
file: () => t`file is required`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export function DisplaySettings() {
|
|||||||
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
|
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
|
||||||
|
|
||||||
<SimpleGrid cols={2}>
|
<SimpleGrid cols={2}>
|
||||||
{(Object.keys(Constants.sharing) as Array<keyof SharingSettings>).map(site => (
|
{(Object.keys(Constants.sharing) as (keyof SharingSettings)[]).map(site => (
|
||||||
<Switch
|
<Switch
|
||||||
key={site}
|
key={site}
|
||||||
label={Constants.sharing[site].label}
|
label={Constants.sharing[site].label}
|
||||||
|
|||||||
@@ -38,9 +38,8 @@ export const useWebSocket = () => {
|
|||||||
ws.onopen = () => dispatch(setWebSocketConnected(true))
|
ws.onopen = () => dispatch(setWebSocketConnected(true))
|
||||||
ws.onclose = () => dispatch(setWebSocketConnected(false))
|
ws.onclose = () => dispatch(setWebSocketConnected(false))
|
||||||
ws.onmessage = event => {
|
ws.onmessage = event => {
|
||||||
const { data } = event
|
if (typeof event.data === "string") {
|
||||||
if (typeof data === "string") {
|
handleMessage(dispatch, event.data)
|
||||||
handleMessage(dispatch, data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ export const locales: Locale[] = [
|
|||||||
|
|
||||||
function activateLocale(locale: string) {
|
function activateLocale(locale: string) {
|
||||||
// lingui
|
// lingui
|
||||||
import(`./locales/${locale}/messages.po`).then(data => {
|
import(`./locales/${locale}/messages.po`).then((data: { messages: Messages }) => {
|
||||||
i18n.load(locale, data.messages as Messages)
|
i18n.load(locale, data.messages)
|
||||||
i18n.activate(locale)
|
i18n.activate(locale)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export function AdminUsersPage() {
|
|||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
</Table.Thead>
|
</Table.Thead>
|
||||||
<Table.Tbody>
|
<Table.Tbody>
|
||||||
{users?.map(u => (
|
{users.map(u => (
|
||||||
<Table.Tr key={u.id}>
|
<Table.Tr key={u.id}>
|
||||||
<Table.Td>{u.id}</Table.Td>
|
<Table.Td>{u.id}</Table.Td>
|
||||||
<Table.Td>{u.name}</Table.Td>
|
<Table.Td>{u.name}</Table.Td>
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import { HistoryService, RedocStandalone } from "redoc"
|
|||||||
|
|
||||||
// disable redoc url sync because it causes issues with hashrouter
|
// disable redoc url sync because it causes issues with hashrouter
|
||||||
Object.defineProperty(HistoryService.prototype, "replace", {
|
Object.defineProperty(HistoryService.prototype, "replace", {
|
||||||
value: () => {},
|
value: () => {
|
||||||
|
// do nothing
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
function ApiDocumentationPage() {
|
function ApiDocumentationPage() {
|
||||||
|
|||||||
@@ -49,11 +49,17 @@ export function FeedEntriesPage(props: FeedEntriesPageProps) {
|
|||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const titleClicked = () => {
|
const titleClicked = () => {
|
||||||
if (props.sourceType === "category") {
|
switch (props.sourceType) {
|
||||||
dispatch(redirectToCategoryDetails(id))
|
case "category":
|
||||||
} else if (props.sourceType === "feed") {
|
dispatch(redirectToCategoryDetails(id))
|
||||||
dispatch(redirectToFeedDetails(id))
|
break
|
||||||
} else if (props.sourceType === "tag") dispatch(redirectToTagDetails(id))
|
case "feed":
|
||||||
|
dispatch(redirectToFeedDetails(id))
|
||||||
|
break
|
||||||
|
case "tag":
|
||||||
|
dispatch(redirectToTagDetails(id))
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user