Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

955 improve performance #973

Merged
merged 6 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions database/002-create-image-table.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
-- SPDX-FileCopyrightText: 2022 - 2023 Netherlands eScience Center
-- SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
-- SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <[email protected]>
-- SPDX-FileCopyrightText: 2022 Netherlands eScience Center
-- SPDX-FileCopyrightText: 2022 dv4all
-- SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
--
-- SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -41,6 +42,7 @@ CREATE TRIGGER sanitise_update_image BEFORE UPDATE ON image FOR EACH ROW EXECUTE

-- ----------------------------------------
-- RPC to get image by id => sha-1 of data
-- cache incrased to 1 year based on lighthouse audit
-- ----------------------------------------

CREATE FUNCTION get_image(uid VARCHAR(40)) RETURNS BYTEA STABLE LANGUAGE plpgsql AS
Expand All @@ -52,7 +54,7 @@ BEGIN
SELECT format(
'[{"Content-Type": "%s"},'
'{"Content-Disposition": "inline; filename=\"%s\""},'
'{"Cache-Control": "max-age=259200"}]',
'{"Cache-Control": "max-age=31536001"}]',
mime_type,
uid)
FROM image WHERE id = uid INTO headers;
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ services:
# dockerfile to use for build
dockerfile: Dockerfile
# update version number to correspond to frontend/package.json
image: rsd/frontend:2.0.0
image: rsd/frontend:2.0.1
environment:
# it uses values from .env file
- POSTGREST_URL
Expand Down
6 changes: 4 additions & 2 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# SPDX-FileCopyrightText: 2021 - 2022 Dusan Mijatovic (dv4all)
# SPDX-FileCopyrightText: 2021 - 2022 dv4all
# SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
# SPDX-FileCopyrightText: 2023 Netherlands eScience Center
#
# SPDX-License-Identifier: Apache-2.0

Expand All @@ -10,7 +12,7 @@
# ----------------------------------------
# 1. Install dependencies only when needed
# ----------------------------------------
FROM node:18.5-buster-slim AS deps
FROM node:20.5-slim AS deps

WORKDIR /app

Expand Down Expand Up @@ -45,7 +47,7 @@ RUN yarn build
# ----------------------------------------
# 3. Production image (standalone mode)
# ----------------------------------------
FROM node:18.5-buster-slim AS runner
FROM node:20.5-slim AS runner

# optional install updates
# RUN apt-get upgrade -y
Expand Down
33 changes: 27 additions & 6 deletions frontend/auth/api/useLoginProviders.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,46 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {useEffect, useState} from 'react'

import {Provider} from 'pages/api/fe/auth'

// save info after initial call
let loginProviders:Provider[] = []

export default function useLoginProviders() {
const [providers, setProviders] = useState<Provider[]>([])

// console.group('useLoginProviders')
// console.log('providers...', providers)
// console.log('loginProviders...', loginProviders)
// console.groupEnd()

useEffect(() => {
let abort = false

async function getProviders() {
const url = '/api/fe/auth'
const resp = await fetch(url)
if (resp.status === 200 && abort === false) {
const providers: Provider[] = await resp.json()
if (abort) return
setProviders(providers)
if (loginProviders.length === 0){
const url = '/api/fe/auth'
const resp = await fetch(url)
if (resp.status === 200 && abort === false) {
const providers: Provider[] = await resp.json()
if (abort) return
setProviders(providers)
// api response is the same once the app is started
// because the info eventually comes from .env file
// to avoid additional api calls we save api response
// into the loginProviders variable and reuse it
loginProviders = [
...providers
]
}
}else if (abort===false){
setProviders(loginProviders)
}
}
if (abort === false) {
Expand Down
16 changes: 14 additions & 2 deletions frontend/components/AppHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,20 @@ export default function AppHeader() {
className="flex-1 flex flex-col px-4 xl:flex-row items-start lg:container lg:mx-auto">
<div className="w-full flex-1 flex items-center justify-between">
<Link href="/" passHref className="hover:text-inherit" aria-label="Link to home page">
<LogoApp className="hidden 2xl:block"/>
<LogoAppSmall className="block 2xl:hidden"/>
<LogoApp
className="hidden 2xl:block"
loading='eager'
// lighthouse audit requires explicit width and height
width="100%"
height="1.5rem"
/>
<LogoAppSmall
className="2xl:hidden"
loading='eager'
// lighthouse audit requires explicit width and height
width="100%"
height="1.5rem"
/>
</Link>

<GlobalSearchAutocomplete className="hidden xl:block ml-12 mr-6"/>
Expand Down
3 changes: 3 additions & 0 deletions frontend/components/layout/ImageWithPlaceholder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export default function ImageWithPlaceholder({
title={placeholder ?? alt}
role="img"
src={src}
// lighthouse audit requires explicit width and height
height="100%"
width="100%"
style={{
objectFit: bgSize,
objectPosition: bgPosition
Expand Down
7 changes: 5 additions & 2 deletions frontend/components/layout/LogoAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -19,13 +21,14 @@ export default function LogoAvatar({name,src,sx,...props}:LogoAvatarProps) {
alt={name}
src={src}
sx={{
// lighthouse audit requires explicit width and height
width: '100%',
height: '100%',
fontSize: '3rem',
'& img': {
height: 'auto',
// height: 'auto',
maxHeight: '100%',
width: 'auto',
// width: 'auto',
maxWidth: '100%'
},
...sx
Expand Down
2 changes: 0 additions & 2 deletions frontend/components/login/LoginButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ import useLoginProviders from '~/auth/api/useLoginProviders'
import {getUserMenuItems} from '~/config/userMenuItems'
import UserMenu from '~/components/layout/UserMenu'
import LoginDialog from './LoginDialog'
import useRsdSettings from '~/config/useRsdSettings'

export default function LoginButton() {
const {host} = useRsdSettings()
const providers = useLoginProviders()
const {session} = useAuth()
const status = session?.status || 'loading'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all) (dv4all)
// SPDX-FileCopyrightText: 2022 - 2023 dv4all
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Ewan Cahen (Netherlands eScience Center) <[email protected]>
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
//
Expand All @@ -21,7 +22,7 @@ import projectState from '../__mocks__/editProjectState'

const mockGetImpactForProject = jest.fn((props) => Promise.resolve(mockImpactForProject))
jest.mock('~/utils/getProjects', () => ({
getImpactForProject: jest.fn((props)=>mockGetImpactForProject(props))
getMentionsForProject: jest.fn((props)=>mockGetImpactForProject(props))
}))

const mockGetMentionByDoiFromRsd = jest.fn((props) => Promise.resolve([] as any))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2023 Ewan Cahen (Netherlands eScience Center) <[email protected]>
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
Expand All @@ -10,7 +11,7 @@ import ImportMentions from '~/components/mention/ImportMentions/index'
import ImportMentionsInfoPanel from '~/components/mention/ImportMentions/ImportMentionsInfoPanel'
import useEditMentionReducer from '~/components/mention/useEditMentionReducer'
import useProjectContext from '~/components/projects/edit/useProjectContext'
import {getImpactForProject} from '~/utils/getProjects'
import {getMentionsForProject} from '~/utils/getProjects'
import {cfgImpact as config} from './config'

export default function ImportProjectImpact() {
Expand All @@ -20,7 +21,7 @@ export default function ImportProjectImpact() {

async function reloadImpact() {
setLoading(true)
const data = await getImpactForProject({project: project.id, token: token, frontend: true})
const data = await getMentionsForProject({project: project.id,table:'impact_for_project',token: token})
setMentions(data)
setLoading(false)
}
Expand Down
11 changes: 6 additions & 5 deletions frontend/components/projects/edit/impact/useImpactForProject.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {useEffect, useState} from 'react'
import {getImpactForProject} from '~/utils/getProjects'
import {getMentionsForProject} from '~/utils/getProjects'

import {sortOnNumProp} from '~/utils/sortFn'
import useEditMentionReducer from '~/components/mention/useEditMentionReducer'
Expand All @@ -24,11 +26,10 @@ export default function useImpactForProject({project, token}: ImpactForProjectPr
let abort = false
async function getImpactFromApi() {
setLoading(true)
// TODO! this request is made two times, investigate
const mentionsForProject = await getImpactForProject({
const mentionsForProject = await getMentionsForProject({
project,
token,
frontend: true
table:'impact_for_project',
token
})
if (mentionsForProject && abort === false) {
const mentions:MentionItemProps[] = mentionsForProject.sort((a, b) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) (dv4all)
// SPDX-FileCopyrightText: 2023 Ewan Cahen (Netherlands eScience Center) <[email protected]>
Expand All @@ -22,7 +23,7 @@ import outputForProject from './__mocks__/outputForProject.json'
// MOCK getOutputForProject
const mockGetOutputForProject = jest.fn((props) => Promise.resolve(outputForProject))
jest.mock('~/utils/getProjects', () => ({
getOutputForProject: jest.fn((props)=>mockGetOutputForProject(props))
getMentionsForProject: jest.fn((props)=>mockGetOutputForProject(props))
}))
// MOCK getMentionByDoiFromRsd
const mockGetMentionByDoiFromRsd = jest.fn((props) => Promise.resolve([] as any))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// SPDX-License-Identifier: Apache-2.0

import {useSession} from '~/auth'
import {getOutputForProject} from '~/utils/getProjects'
import {getMentionsForProject} from '~/utils/getProjects'
import ImportMentions from '~/components/mention/ImportMentions/index'
import ImportMentionsInfoPanel from '~/components/mention/ImportMentions/ImportMentionsInfoPanel'
import useEditMentionReducer from '~/components/mention/useEditMentionReducer'
Expand All @@ -21,7 +21,7 @@ export default function ImportProjectOutput() {

async function reloadOutput() {
setLoading(true)
const data = await getOutputForProject({project: project.id, token: token, frontend: true})
const data = await getMentionsForProject({project: project.id,table:'output_for_project',token: token})
setMentions(data)
setLoading(false)
}
Expand Down
17 changes: 7 additions & 10 deletions frontend/components/projects/edit/output/useOutputForProject.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {useEffect, useState} from 'react'
import useEditMentionReducer from '~/components/mention/useEditMentionReducer'
import {MentionItemProps} from '~/types/Mention'
import {getOutputForProject} from '~/utils/getProjects'
import {getMentionsForProject} from '~/utils/getProjects'
import {sortOnNumProp} from '~/utils/sortFn'

type OutputForProjectProps = {
Expand All @@ -22,10 +24,10 @@ export default function useOutputForProject({project, token}: OutputForProjectPr
let abort = false
async function getImpact() {
setLoading(true)
const mentions = await getOutputForProject({
const mentions = await getMentionsForProject({
project,
token,
frontend: true
table:'output_for_project',
token
})
const output:MentionItemProps[] = mentions.sort((a, b) => {
// sort mentions on publication year, newest at the top
Expand All @@ -41,12 +43,7 @@ export default function useOutputForProject({project, token}: OutputForProjectPr
if (project && token && project!==loadedProject) {
getImpact()
}
// else {
// console.group('skip request useOutputForProject')
// console.log('project...', project)
// console.log('loadedProject...', loadedProject)
// console.groupEnd()
// }

return () => { abort = true }
// we skip setMentions and setLoading methods in the deps to avoid loop
// TODO! try wrapping methods of useEditMentionReducer in useCallback?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import useValidateImageSrc from '~/utils/useValidateImageSrc'

export default function ListImageWithGradientPlaceholder({imgSrc,alt}:{imgSrc:string|null, alt:string|null}) {
const validImg = useValidateImageSrc(imgSrc)

// console.group('ListItemImageWithGradientPlaceholder')
// console.log('imgSrc...', imgSrc)
// console.log('validImg...', validImg)
// console.groupEnd()

if (validImg === false || imgSrc === null){
// return gradient square as placeholder
return (
<div
className="w-12 self-stretch bg-gradient-to-br from-base-300 from-0% via-base-100 via-50% to-base-100"
/>
)
}

return (
<img
src={`${imgSrc ?? ''}`}
alt={alt ?? 'Image'}
className="w-12 max-h-[3.5rem] text-base-content-disabled p-2 object-contain object-center"
// lighthouse audit requires explicit width and height
height="2.5rem"
width="100%"
/>
)
}
Loading