kopia lustrzana https://github.com/Stopka/fedisearch
Codestyle fixes, deploy fixes
rodzic
82e84c09fe
commit
5e3e152fa6
|
@ -1,2 +1,3 @@
|
||||||
application/node_modules
|
application/node_modules
|
||||||
application/src/.next
|
application/src/.next
|
||||||
|
application/src/.vscode
|
||||||
|
|
|
@ -4,6 +4,7 @@ WORKDIR /srv
|
||||||
COPY application/package*.json ./
|
COPY application/package*.json ./
|
||||||
RUN npm install --frozen-lockfile
|
RUN npm install --frozen-lockfile
|
||||||
COPY application/. .
|
COPY application/. .
|
||||||
|
RUN chmod -R uog+r .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM build as dev
|
FROM build as dev
|
||||||
|
@ -17,6 +18,7 @@ EXPOSE 3000
|
||||||
WORKDIR /srv
|
WORKDIR /srv
|
||||||
COPY --from=build /srv/node_modules ./node_modules
|
COPY --from=build /srv/node_modules ./node_modules
|
||||||
COPY --from=build /srv/package*.json ./
|
COPY --from=build /srv/package*.json ./
|
||||||
|
COPY --from=build /srv/next.config.js ./
|
||||||
COPY --from=build --chown=nextjs:nodejs /srv/src/.next ./.next
|
COPY --from=build --chown=nextjs:nodejs /srv/src/.next ./.next
|
||||||
COPY --from=build /srv/src/public ./public
|
COPY --from=build /srv/src/public ./public
|
||||||
CMD node_modules/.bin/next start
|
CMD node_modules/.bin/next start
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev ./src --hostname 0.0.0.0",
|
"dev": "next dev ./src --hostname 0.0.0.0",
|
||||||
"build": "next build ./src",
|
"build": "next build ./src",
|
||||||
"start": "next start ./src",
|
"start": "next start",
|
||||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||||
"generate:graphql-types": "graphql-codegen-esm --config graphql-codegen.yml"
|
"generate:graphql-types": "graphql-codegen-esm --config graphql-codegen.yml"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import React, {ReactElement, ReactNode} from "react";
|
import React, { ReactElement, ReactNode } from 'react'
|
||||||
|
|
||||||
export default function ResponsiveTable({children, className}: {
|
export default function ResponsiveTable ({ children, className }: {
|
||||||
children: ReactNode,
|
children: ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return (
|
return (
|
||||||
<div className={'table-responsive'}>
|
<div className={'table-responsive'}>
|
||||||
<table className={`table table-dark table-striped table-bordered nodes ${className??''}`}>
|
<table className={`table table-dark table-striped table-bordered nodes ${className ?? ''}`}>
|
||||||
{children}
|
{children}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
'use client'
|
'use client'
|
||||||
import {faCircle} from "@fortawesome/free-solid-svg-icons";
|
import { faCircle } from '@fortawesome/free-solid-svg-icons'
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import React, {ReactElement} from "react";
|
import React, { ReactElement } from 'react'
|
||||||
|
|
||||||
export default function SoftwareBadgePlaceholder():ReactElement{
|
export default function SoftwareBadgePlaceholder (): ReactElement {
|
||||||
return <div className={'software-name placeholder-glow'}>
|
return <div className={'software-name placeholder-glow'}>
|
||||||
<FontAwesomeIcon icon={faCircle} className={'icon'}/>
|
<FontAwesomeIcon icon={faCircle} className={'icon'}/>
|
||||||
<span className={'value placeholder col-6'}/>
|
<span className={'value placeholder col-6'}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
'use client'
|
'use client'
|
||||||
import React, {ReactElement, ReactNode, useContext, useState} from "react";
|
import React, { ReactElement, ReactNode, useContext, useState } from 'react'
|
||||||
|
|
||||||
const AccordionContext = React.createContext<{
|
const AccordionContext = React.createContext<{
|
||||||
expandedId: string | undefined,
|
expandedId: string | undefined
|
||||||
setExpandedId: (id: string | undefined) => void
|
setExpandedId: (id: string | undefined) => void
|
||||||
} | undefined>(undefined)
|
} | undefined>(undefined)
|
||||||
|
|
||||||
export const useAccordion = (id: string): [boolean, () => void] => {
|
export const useAccordion = (id: string): [boolean, () => void] => {
|
||||||
const context = useContext(AccordionContext)
|
const context = useContext(AccordionContext)
|
||||||
if (context === undefined) {
|
if (context === undefined) {
|
||||||
throw new Error('Hook useAccordion needs to be used in Accordion element')
|
throw new Error('Hook useAccordion needs to be used in Accordion element')
|
||||||
|
}
|
||||||
|
const { expandedId, setExpandedId } = context
|
||||||
|
return [
|
||||||
|
expandedId === id,
|
||||||
|
() => {
|
||||||
|
setExpandedId(expandedId === id ? undefined : id)
|
||||||
}
|
}
|
||||||
const {expandedId, setExpandedId} = context;
|
]
|
||||||
return [
|
|
||||||
expandedId === id,
|
|
||||||
() => {
|
|
||||||
setExpandedId(expandedId === id ? undefined : id)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Accordion({children}: {
|
export default function Accordion ({ children }: {
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const [expandedId, setExpandedId] = useState<string | undefined>(undefined)
|
const [expandedId, setExpandedId] = useState<string | undefined>(undefined)
|
||||||
return <AccordionContext.Provider value={{expandedId, setExpandedId}}>
|
return <AccordionContext.Provider value={{ expandedId, setExpandedId }}>
|
||||||
<div className="accordion" id="accordionExample">
|
<div className="accordion" id="accordionExample">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
'use client'
|
'use client'
|
||||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import { FeedQueryInput } from '../../graphql/generated/types'
|
import { FeedQueryInput } from '../../graphql/generated/types'
|
||||||
import SearchInput from "../form/SearchInput";
|
import SearchInput from '../form/SearchInput'
|
||||||
import SubmitButton from "../form/SubmitButton";
|
import SubmitButton from '../form/SubmitButton'
|
||||||
|
|
||||||
export default function FeedForm (
|
export default function FeedForm (
|
||||||
{ onSubmit, onQueryChange, query }: {
|
{ onSubmit, onQueryChange, query }: {
|
||||||
|
@ -42,7 +41,7 @@ export default function FeedForm (
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
faIcon={faSearch}
|
faIcon={faSearch}
|
||||||
label={'Search'}
|
label={'Search'}
|
||||||
id={"search-feeds-button"}
|
id={'search-feeds-button'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import {ReactElement, ReactNode} from "react";
|
import React, { ReactElement, ReactNode } from 'react'
|
||||||
|
|
||||||
export default function FeedInfo({children, show}: { children?: ReactNode, show?: boolean }): ReactElement {
|
export default function FeedInfo ({ children, show }: { children?: ReactNode, show?: boolean }): ReactElement {
|
||||||
if (show === false) {
|
if (show === false) {
|
||||||
return <>{children}</>
|
return <>{children}</>
|
||||||
}
|
}
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { faCircle } from '@fortawesome/free-solid-svg-icons'
|
import { faCircle } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import SoftwareBadge from "../SoftwareBadge";
|
import SoftwareBadgePlaceholder from '../SoftwareBadgePlaceholder'
|
||||||
import SoftwareBadgePlaceholder from "../SoftwareBadgePlaceholder";
|
|
||||||
import Avatar from './Avatar'
|
import Avatar from './Avatar'
|
||||||
import Badge from './badges/Badge'
|
import Badge from './badges/Badge'
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import React, {ChangeEventHandler, ReactElement} from "react";
|
import React, { ChangeEventHandler, ReactElement } from 'react'
|
||||||
|
|
||||||
export default function SearchInput({label, onChange, value, describedBy}: {
|
export default function SearchInput ({ label, onChange, value, describedBy }: {
|
||||||
label: string,
|
label: string
|
||||||
onChange?: ChangeEventHandler,
|
onChange?: ChangeEventHandler
|
||||||
value?: string,
|
value?: string
|
||||||
describedBy?: string
|
describedBy?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return <input
|
return <input
|
||||||
name={'search'}
|
name={'search'}
|
||||||
id={'search'}
|
id={'search'}
|
||||||
type={'search'}
|
type={'search'}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import {IconProp} from "@fortawesome/fontawesome-svg-core";
|
import { IconProp } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import React, {ReactElement} from "react";
|
import React, { ReactElement } from 'react'
|
||||||
|
|
||||||
export default function SubmitButton({faIcon, label, id}: {
|
export default function SubmitButton ({ faIcon, label, id }: {
|
||||||
faIcon: IconProp,
|
faIcon: IconProp
|
||||||
label: string,
|
label: string
|
||||||
id?: string
|
id?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return <button type={'submit'} className={'btn btn-primary'} id={id}>
|
return <button type={'submit'} className={'btn btn-primary'} id={id}>
|
||||||
<FontAwesomeIcon icon={faIcon}/>
|
<FontAwesomeIcon icon={faIcon}/>
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
'use client'
|
'use client'
|
||||||
import {faSearch} from '@fortawesome/free-solid-svg-icons'
|
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||||
import React, {ReactElement} from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import {NodeQueryInput} from '../../graphql/generated/types'
|
import { NodeQueryInput } from '../../graphql/generated/types'
|
||||||
import SearchInput from "../form/SearchInput";
|
import SearchInput from '../form/SearchInput'
|
||||||
import SubmitButton from "../form/SubmitButton";
|
import SubmitButton from '../form/SubmitButton'
|
||||||
|
|
||||||
export default function NodeForm(
|
export default function NodeForm (
|
||||||
{onSubmit, onQueryChange, query}: {
|
{ onSubmit, onQueryChange, query }: {
|
||||||
onSubmit: () => void
|
onSubmit: () => void
|
||||||
onQueryChange: (query: NodeQueryInput) => void
|
onQueryChange: (query: NodeQueryInput) => void
|
||||||
query: NodeQueryInput
|
query: NodeQueryInput
|
||||||
}
|
}
|
||||||
): ReactElement {
|
): ReactElement {
|
||||||
const handleQueryChange = (event): void => {
|
const handleQueryChange = (event): void => {
|
||||||
const inputElement = event.target
|
const inputElement = event.target
|
||||||
const value = inputElement.value
|
const value = inputElement.value
|
||||||
const name = inputElement.name
|
const name = inputElement.name
|
||||||
const newQuery = {
|
const newQuery = {
|
||||||
...query
|
...query
|
||||||
}
|
|
||||||
newQuery[name] = value
|
|
||||||
onQueryChange(newQuery)
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
}
|
||||||
|
newQuery[name] = value
|
||||||
|
onQueryChange(newQuery)
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
const handleSubmit = (event): void => {
|
const handleSubmit = (event): void => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
onSubmit()
|
onSubmit()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className={'input-group mb-3'}>
|
<div className={'input-group mb-3'}>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
|
@ -45,5 +45,5 @@ export default function NodeForm(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import React, {ReactElement} from "react";
|
import React, { ReactElement } from 'react'
|
||||||
import {NodeQueryInput, NodeSortingByEnum} from "../../graphql/generated/types";
|
import { NodeQueryInput, NodeSortingByEnum } from '../../graphql/generated/types'
|
||||||
import SortToggle from "../SortToggle";
|
import SortToggle from '../SortToggle'
|
||||||
|
|
||||||
export default function NodeHeader({query,onSortToggle}:{
|
export default function NodeHeader ({ query, onSortToggle }: {
|
||||||
query: NodeQueryInput
|
query: NodeQueryInput
|
||||||
onSortToggle: (sortBy: NodeSortingByEnum)=> void
|
onSortToggle: (sortBy: NodeSortingByEnum) => void
|
||||||
}):ReactElement{
|
}): ReactElement {
|
||||||
return (
|
return (
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th rowSpan={2}>
|
<th rowSpan={2}>
|
||||||
|
@ -59,5 +59,5 @@ export default function NodeHeader({query,onSortToggle}:{
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
import React, {ReactElement} from "react";
|
import React, { ReactElement } from 'react'
|
||||||
import {ListNodesItemFragment} from "../../graphql/generated/types";
|
import { ListNodesItemFragment } from '../../graphql/generated/types'
|
||||||
import NodeResult from "./NodeResult";
|
import NodeResult from './NodeResult'
|
||||||
|
|
||||||
export default function NodeResults({nodes}:{
|
export default function NodeResults ({ nodes }: {
|
||||||
nodes:ListNodesItemFragment[]|undefined,
|
nodes: ListNodesItemFragment[] | undefined
|
||||||
}):ReactElement{
|
}): ReactElement {
|
||||||
if(nodes === undefined){
|
if (nodes === undefined) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tbody>
|
<tbody>
|
||||||
{(nodes.length > 0)
|
{(nodes.length > 0)
|
||||||
? nodes.map((node, index) => {
|
? nodes.map((node, index) => {
|
||||||
return (
|
return (
|
||||||
<NodeResult node={node} key={index}/>
|
<NodeResult node={node} key={index}/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
: (
|
: (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={9}>No servers found</td>
|
<td colSpan={9}>No servers found</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client'
|
'use client'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
|
||||||
import { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
ListStatsDocument,
|
ListStatsDocument,
|
||||||
SortingWayEnum, StatsAggregationFragment,
|
SortingWayEnum, StatsAggregationFragment,
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import {ReactElement} from "react";
|
import React, { ReactElement } from 'react'
|
||||||
import {StatsAggregationFragment} from "../../graphql/generated/types";
|
import { StatsAggregationFragment } from '../../graphql/generated/types'
|
||||||
|
|
||||||
export default function StatsFooter({sumAggregation}: { sumAggregation: StatsAggregationFragment | undefined }): ReactElement {
|
export default function StatsFooter ({ sumAggregation }: { sumAggregation: StatsAggregationFragment | undefined }): ReactElement {
|
||||||
return (
|
return (
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Summary</th>
|
<th>Summary</th>
|
||||||
<th className={'text-end'}>{sumAggregation?.nodeCount??0}</th>
|
<th className={'text-end'}>{sumAggregation?.nodeCount ?? 0}</th>
|
||||||
<th className={'text-end'}>{sumAggregation?.accountFeedCount??0}</th>
|
<th className={'text-end'}>{sumAggregation?.accountFeedCount ?? 0}</th>
|
||||||
<th className={'text-end'}>{sumAggregation?.channelFeedCount??0}</th>
|
<th className={'text-end'}>{sumAggregation?.channelFeedCount ?? 0}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
'use client'
|
'use client'
|
||||||
import {ReactElement} from "react";
|
import React, { ReactElement } from 'react'
|
||||||
import {NodeSortingByEnum, StatsQueryInput, StatsSortingByEnum} from "../../graphql/generated/types";
|
import { StatsQueryInput, StatsSortingByEnum } from '../../graphql/generated/types'
|
||||||
import SortToggle from "../SortToggle";
|
import SortToggle from '../SortToggle'
|
||||||
|
|
||||||
export default function StatsHeader({query,onSortToggle}: {
|
export default function StatsHeader ({ query, onSortToggle }: {
|
||||||
query: StatsQueryInput,
|
query: StatsQueryInput
|
||||||
onSortToggle: (sortBy: StatsSortingByEnum) => void
|
onSortToggle: (sortBy: StatsSortingByEnum) => void
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return <thead>
|
return <thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<SortToggle onToggle={onSortToggle} field={'softwareName'} sort={query}>
|
<SortToggle onToggle={onSortToggle} field={'softwareName'} sort={query}>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import { StatsAggregationFragment, StatsItemFragment } from '../../graphql/generated/types'
|
import { StatsAggregationFragment, StatsItemFragment } from '../../graphql/generated/types'
|
||||||
import StatsResult from './StatsResult'
|
import StatsResult from './StatsResult'
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue