Skip to content

Commit

Permalink
Merge pull request #2665 from GlobalFishingWatch/image-labeler/kick-off
Browse files Browse the repository at this point in the history
Image labeler
  • Loading branch information
j8seangel authored Jun 6, 2024
2 parents 4f4655d + 52fb05c commit a28d078
Show file tree
Hide file tree
Showing 48 changed files with 3,220 additions and 275 deletions.
2 changes: 1 addition & 1 deletion apps/api-portal/cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ steps:
waitFor: ['restore_cache']
name: node:21
script: |
yarn set version 4.1.1
yarn set version 4.2.2
yarn -v
yarn install --immutable
Expand Down
2 changes: 1 addition & 1 deletion apps/deck-playground/cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ steps:
waitFor: ['restore_cache']
name: node:21
script: |
yarn set version 4.1.1
yarn set version 4.2.2
yarn -v
yarn install --immutable
Expand Down
2 changes: 1 addition & 1 deletion apps/fishing-map-e2e/cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ steps:
waitFor: ['restore_cache']
name: node:21
script: |
yarn set version 4.1.1
yarn set version 4.2.2
yarn -v
yarn install --immutable
Expand Down
2 changes: 1 addition & 1 deletion apps/fishing-map/cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ steps:
waitFor: ['restore_cache']
name: node:21
script: |
yarn set version 4.1.1
yarn set version 4.2.2
yarn -v
yarn install --immutable
Expand Down
18 changes: 18 additions & 0 deletions apps/image-labeler/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.js"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
24 changes: 24 additions & 0 deletions apps/image-labeler/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#################################################################################
# Generate htpasswd file
#################################################################################
# FROM appsoa/docker-alpine-htpasswd as htpasswd
# ARG BASIC_AUTH_USER=gfw
# ARG BASIC_AUTH_PASS=default
# ENV BASIC_AUTH_USER $BASIC_AUTH_USER
# ENV BASIC_AUTH_PASS $BASIC_AUTH_PASS
# RUN htpasswd -Bbn "$BASIC_AUTH_USER" "$BASIC_AUTH_PASS" > /home/.htpasswd

#################################################################################
# Actual application to run
#################################################################################
# Using stable version that uses alpine 3.14 to fix build errors
# https://github.com/alpinelinux/docker-alpine/issues/182
FROM nginx:stable-alpine as production

COPY ./nginx.conf /etc/nginx/nginx.template
# COPY --from=htpasswd /home/.htpasswd /home/.htpasswd
# RUN cat /home/.htpasswd >> /etc/nginx/.htpasswd
COPY ./entrypoint.sh entrypoint.sh
COPY ./ /usr/share/nginx/www/
ENTRYPOINT ["./entrypoint.sh"]

104 changes: 104 additions & 0 deletions apps/image-labeler/cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
steps:
- name: 'gcr.io/$PROJECT_ID/restore_cache'
id: restore_cache
waitFor: ['-']
script: |
#!/usr/bin/env bash
restore_cache \
--bucket=gs://frontend-cache-dependencies \
--key=node_modules-$( checksum yarn.lock )
restore_cache \
--bucket=gs://frontend-cache-dependencies \
--key=yarn-$( checksum yarn.lock )
restore_cache \
--bucket=gs://frontend-cache-dependencies \
--key=yarn-install-state-$( checksum yarn.lock )
- id: 'install-yarn'
waitFor: ['restore_cache']
name: node:21
script: |
yarn set version 4.2.2
yarn -v
yarn install --immutable
- id: 'save_cache'
waitFor: ['install-yarn']
name: 'gcr.io/$PROJECT_ID/restore_cache'
script: |
#!/usr/bin/env bash
save_cache \
--bucket=gs://frontend-cache-dependencies \
--key=node_modules-$( checksum yarn.lock ) \
--path=./node_modules \
--no-clobber
save_cache \
--bucket=gs://frontend-cache-dependencies \
--key=yarn-$( checksum yarn.lock ) \
--path=.yarn/cache \
--no-clobber
save_cache \
--bucket=gs://frontend-cache-dependencies \
--key=yarn-install-state-$( checksum yarn.lock ) \
--path=.yarn/install-state.gz \
--no-clobber
- id: 'build-app'
waitFor: ['install-yarn']
name: node:21
entrypoint: yarn
args: ['nx', 'build', 'image-labeler', '--parallel']
env:
- 'NX_BRANCH=$_NX_BRANCH'
- 'NX_CLOUD_AUTH_TOKEN=$_NX_CLOUD_AUTH_TOKEN'
- 'API_GATEWAY=$_API_GATEWAY'

- name: 'gcr.io/kaniko-project/executor:latest'
id: 'build-image'
waitFor: ['build-app']
args:
[
'--destination=gcr.io/world-fishing-827/github.com/globalfishingwatch/image-labeler:$SHORT_SHA',
'--cache=true',
'--build-arg',
'BASIC_AUTH_USER=$_BASIC_AUTH_USER',
'--build-arg',
'BASIC_AUTH_PASS=$_BASIC_AUTH_PASS',
'--target',
'production',
'-f',
'./apps/image-labeler/Dockerfile',
'-c',
'./dist/apps/image-labeler',
]

# Deploy to the appropriate environment
- name: 'gcr.io/cloud-builders/gcloud'
waitFor: ['build-image']
id: 'deploy-cloud-run'
entrypoint: 'bash'
env:
- '_RUN_SERVICE_NAME=$_RUN_SERVICE_NAME'
args:
- '-eEuo'
- 'pipefail'
- '-c'
- |-
branch_service_name=`echo image-labeler-$BRANCH_NAME | sed -r 's,[/\.],-,g' | awk '{print substr(tolower($0),0,62)}'`
service_name=${_RUN_SERVICE_NAME:-${branch_service_name}}
gcloud beta run deploy \
$service_name \
--project \
$_RUN_PROJECT \
--image \
gcr.io/world-fishing-827/github.com/globalfishingwatch/image-labeler:$SHORT_SHA \
--region \
$_RUN_REGION \
--platform managed \
--set-env-vars \
BASIC_AUTH=$_BASIC_AUTH \
--allow-unauthenticated
timeout: 1800s
options:
machineType: 'E2_HIGHCPU_8'
14 changes: 14 additions & 0 deletions apps/image-labeler/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
image-labeler:
build:
context: ../../dist/apps/image-labeler
dockerfile: ../../../apps/image-labeler/Dockerfile
target: production
container_name: image-labeler
ports:
- 3000:80
env_file:
- .env
environment:
- PORT=80
- API_GATEWAY=https://gateway.api.dev.globalfishingwatch.org
16 changes: 16 additions & 0 deletions apps/image-labeler/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>ImageLabeler</title>
<base href="/" />

<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
48 changes: 48 additions & 0 deletions apps/image-labeler/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
events {
worker_connections 1024;
}

http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
client_header_buffer_size 64k;
large_client_header_buffers 4 64k;

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;

gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Specify the minimum length of the response to compress (default 20)
gzip_min_length 100;

server {
listen ${PORT};
root /usr/share/nginx/www/;

location ~* ^/image-labeler/(.+\..+)$ {
alias /usr/share/nginx/www/$1;
}

location ~* ^/(.+\..+)$ {
alias /usr/share/nginx/www/$1;
}

location / {
# auth_basic ${BASIC_AUTH};
# auth_basic_user_file /etc/nginx/.htpasswd;
try_files /index.html =404;
}
}
}
57 changes: 57 additions & 0 deletions apps/image-labeler/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "image-labeler",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/image-labeler/src",
"projectType": "application",
"tags": [],
"targets": {
"build": {
"executor": "@nx/vite:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"outputPath": "dist/apps/image-labeler"
},
"configurations": {
"development": {
"mode": "development"
},
"production": {
"mode": "production"
}
}
},
"start": {
"executor": "@nx/vite:dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "image-labeler:build"
},
"configurations": {
"development": {
"buildTarget": "image-labeler:build:development",
"hmr": true
},
"production": {
"buildTarget": "image-labeler:build:production",
"hmr": false
}
}
},
"preview": {
"executor": "@nx/vite:preview-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "image-labeler:build"
},
"configurations": {
"development": {
"buildTarget": "image-labeler:build:development"
},
"production": {
"buildTarget": "image-labeler:build:production"
}
}
}
}
}
Binary file added apps/image-labeler/public/favicon.ico
Binary file not shown.
31 changes: 31 additions & 0 deletions apps/image-labeler/src/api/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { BaseQueryFn } from '@reduxjs/toolkit/query/react'
import { GFWAPI, ParsedAPIError, parseAPIError } from '@globalfishingwatch/api-client'

export const gfwBaseQuery =
<Response = any>(
{ baseUrl, method }: { baseUrl: string; method?: 'GET' | 'POST' } = {
baseUrl: '',
method: 'GET',
}
): BaseQueryFn<
{
url: string
signal?: AbortSignal
body?: any
},
Response,
ParsedAPIError
> =>
async ({ url, signal, body }) => {
try {
const data = await GFWAPI.fetch<Response>(baseUrl + url, { signal, method, body })
if (!data) {
return { data: body }
}
return { data }
} catch (gfwApiError: any) {
return {
error: parseAPIError(gfwApiError),
}
}
}
39 changes: 39 additions & 0 deletions apps/image-labeler/src/api/project.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createApi } from '@reduxjs/toolkit/query/react'
import { gfwBaseQuery } from './base'

type LabellingProjectsApiParams = {
projectId: string
limit: number
}

type LabellingProjectsByIdApiParams = {
projectId: string
taskId: string
}

export const projectApi = createApi({
reducerPath: 'projectApi',
baseQuery: gfwBaseQuery({
baseUrl: '/labelling-projects',
}),
endpoints: (builder) => ({
getLabellingProjectTasks: builder.query({
query: ({ projectId, limit }: LabellingProjectsApiParams) => {
return {
url: `/${projectId}/task?limit=${limit}`,
}
},
}),
getLabellingProjectTasksById: builder.query({
query: ({ projectId, taskId }: LabellingProjectsByIdApiParams) => {
return {
url: `/${projectId}/task/${taskId}`,
}
},
}),
}),
})

// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const { useGetLabellingProjectTasksQuery, useGetLabellingProjectTasksByIdQuery } = projectApi
Loading

0 comments on commit a28d078

Please sign in to comment.