Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 11 additions & 0 deletions .github/workflows/aws-proxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ jobs:
with:
python-version: '3.13'

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 20

- name: Enable Corepack and set Yarn version
run: |
corepack enable
corepack prepare yarn@3.2.3 --activate
shell: bash

- name: Set up Terraform CLI
uses: hashicorp/setup-terraform@v2

Expand Down
3 changes: 3 additions & 0 deletions aws-proxy/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
*.tfstate*
.terraform*
node_modules
static
.yarn/
4 changes: 1 addition & 3 deletions aws-proxy/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
recursive-include aws_proxy *.html
recursive-include aws_proxy *.js
recursive-include aws_proxy *.png
exclude aws_proxy/frontend *
39 changes: 32 additions & 7 deletions aws-proxy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ VENV_ACTIVATE = $(VENV_DIR)/bin/activate
VENV_RUN = . $(VENV_ACTIVATE)
TEST_PATH ?= tests
PIP_CMD ?= pip
FRONTEND_FOLDER = aws_proxy/frontend
COREPACK_EXISTS := $(shell command -v corepack)
YARN_EXISTS := $(shell command -v yarn)

venv: $(VENV_ACTIVATE)

usage: ## Show this help
@grep -Fh "##" $(MAKEFILE_LIST) | grep -Fv fgrep | sed -e 's/:.*##\s*/##/g' | awk -F'##' '{ printf "%-25s %s\n", $$1, $$2 }'

install: ## Install dependencies
test -d .venv || $(VENV_BIN) .venv
$(VENV_RUN); pip install -e .
$(VENV_RUN); pip install -e .[test]
touch $(VENV_DIR)/bin/activate

clean: ## Clean up
rm -rf .venv/
rm -rf build/
Expand All @@ -32,7 +31,7 @@ test: ## Run tests
entrypoints: ## Generate plugin entrypoints for Python package
$(VENV_RUN); python -m plux entrypoints

build: entrypoints ## Build the extension
build: entrypoints build-frontend ## Build the extension
$(VENV_RUN); python -m build --no-isolation . --outdir build
@# make sure that the entrypoints are contained in the dist folder and are non-empty
@test -s localstack_extension_aws_proxy.egg-info/entry_points.txt || (echo "Entrypoints were not correctly created! Aborting!" && exit 1)
Expand All @@ -45,6 +44,32 @@ enable: $(wildcard ./build/localstack_extension_aws_proxy-*.tar.gz) ## Enable t
publish: clean-dist venv dist
$(VENV_RUN); pip install --upgrade twine; twine upload dist/*

check-frontend-deps:
@if [ -z "$(YARN_EXISTS)" ]; then \
npm install --global yarn; \
fi
@if [ -z "$(COREPACK_EXISTS)" ]; then \
npm install -g corepack; \
fi

install-frontend: venv check-frontend-deps ## Install dependencies of the frontend
cd $(FRONTEND_FOLDER) && yarn install

build-frontend: # Build the React app
@if [ ! -d "$(FRONTEND_FOLDER)/node_modules" ]; then \
$(MAKE) install-frontend; \
fi
cd $(FRONTEND_FOLDER); rm -rf build && NODE_ENV=prod npm run build

start-frontend: ## Start the frontend in dev mode (hot reload)
cd $(FRONTEND_FOLDER); yarn start

install: install-frontend ## Install dependencies
test -d .venv || $(VENV_BIN) .venv
$(VENV_RUN); pip install -e .
$(VENV_RUN); pip install -e .[test]
touch $(VENV_DIR)/bin/activate

clean-dist: clean
rm -rf dist/

Expand Down
99 changes: 99 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/esbuild.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/* eslint-disable global-require */

const esbuild = require('esbuild');
const path = require('path');

const SvgrPlugin = require('esbuild-plugin-svgr');
const CopyPlugin = require('esbuild-plugin-copy').default;
const CleanPlugin = require('esbuild-plugin-clean').default;
const { NodeModulesPolyfillPlugin } = require('@esbuild-plugins/node-modules-polyfill');

const packageJson = require('../package.json');
const HtmlPlugin = require('./plugins/html');
const { writeFileSync } = require('fs');

const CURRENT_ENV = process.env.NODE_ENV || 'development.local';
const BUILD_PATH = path.join(__dirname, '..', '..', 'server', 'static');

const BUILD_CONFIG = {
entryPoints: [
path.join(__dirname, '..', 'src', 'index.tsx'),
path.join(__dirname, '..', 'src', 'index.html'),
],
assetNames: '[name]-[hash]',
entryNames: '[name]-[hash]',
outdir: BUILD_PATH,
bundle: true,
minify: !CURRENT_ENV.includes('development.local'),
sourcemap: true,
target: 'es2020',
metafile: true,
// splitting: true,
// set in case file loader is added below
plugins: [
CleanPlugin({
patterns: [`${BUILD_PATH}/*`, `!${BUILD_PATH}/index.html`],
sync: true,
verbose: false,
options: {
force: true
}
}),
SvgrPlugin({
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
}),
CopyPlugin({
copyOnStart: true,
// https://github.com/LinbuduLab/nx-plugins/issues/57
assets: [
{
from: ['./public/*'],
to: ['./'],
},
],
}),
NodeModulesPolyfillPlugin(),
HtmlPlugin({
filename: path.join(BUILD_PATH, 'index.html'),
env: true,
}),
],
inject: [path.join(__dirname, 'esbuild.shims.js')],
define: {
// Define replacements for env vars starting with `REACT_APP_`
...Object.entries(process.env).reduce(
(memo, [name, value]) => name.startsWith('REACT_APP_') ?
{ ...memo, [`process.env.${name}`]: JSON.stringify(value) } :
memo,
{},
),
'process.cwd': 'dummyProcessCwd',
global: 'window',
},
external: [
...Object.keys(packageJson.devDependencies || {}),
],
loader: {
'.md': 'text',
'.gif': 'dataurl',
}
};

const build = async (overrides = {}) => {
try {
await esbuild.build({ ...BUILD_CONFIG, ...overrides });
writeFileSync(path.join(BUILD_PATH, '__init__.py'),'')
console.log('done building');
} catch (e) {
console.error(e);
process.exit(1);
}
};

module.exports = { build };
7 changes: 7 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/esbuild.shims.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';

export { React };

export function dummyProcessCwd() {
return '';
};
11 changes: 11 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { build, serve } = require('./esbuild.config');

(async () => {
if (process.argv.includes('--serve')) {
await serve();
} else if (process.argv.includes('--watch')) {
await build({ watch: true });
} else {
await build();
}
})();
84 changes: 84 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/plugins/html/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

/**
* @param {object} config
* @param {string} config.filename - HTML file to process and override
* @param {boolean} config.env - Whether to replace env vars or not (default - `false`)
* @param {string} config.envPrefix - Limit env vars to pick (default - `REACT_APP_`)
*/
const HtmlPlugin = (config) => ({
name: 'html',
setup(build) {
build.onResolve({ filter: /\.html$/ }, args => ({
path: path.resolve(args.resolveDir, args.path),
namespace: 'html',
}));
build.onLoad({ filter: /.html/, namespace: 'html' }, (args) => {
let htmlContent = fs.readFileSync(args.path).toString('utf-8');

// replace env vars
if (config.env) {
const envPrefix = config.envPrefix || 'REACT_APP_';
const envVars = Object.entries(process.env || {}).filter(([name]) => name.startsWith(envPrefix));
htmlContent = envVars.reduce(
(memo, [name, value]) => memo.replace(new RegExp(`%${name}%`, 'igm'), value),
htmlContent,
);
}

return {
contents: htmlContent,
loader: 'file'
};
});

build.onEnd((result) => {
const outFiles = Object.keys((result.metafile || {}).outputs);
const jsFiles = outFiles.filter((p) => p.endsWith('.js'));
const cssFiles = outFiles.filter((p) => p.endsWith('.css'));
const htmlFiles = outFiles.filter((p) => p.endsWith('.html'));

const headerAppends = cssFiles.reduce(
(memo, p) => {
const filename = p.split(path.sep).slice(-1)[0];
return [...memo, `<link href="${filename}" rel="stylesheet">`];
},
[],
);

const bodyAppends = jsFiles.reduce(
(memo, p) => {
const filename = p.split(path.sep).slice(-1)[0];
return [...memo, `<script src="${filename}"></script>`];
},
[],
);

for (const htmlFile of htmlFiles) {
let htmlContent = fs.readFileSync(htmlFile).toString('utf-8');

// replace env vars
if (config.env) {
const envPrefix = config.envPrefix || 'REACT_APP_';
const envVars = Object.entries(process.env).filter(([name]) => name.startsWith(envPrefix));

htmlContent = envVars.reduce(
(memo, [name, value]) => memo.replace(new RegExp(`%${name}%`, 'igm'), value),
htmlContent,
);
}

// inject references to js and css files
htmlContent = htmlContent
.replace('</head>', [...headerAppends, '</head>'].join("\n"))
.replace('</body>', [...bodyAppends, '</body>'].join("\n"));

fs.writeFileSync(config.filename.replace('-[^.]+', ''), htmlContent);
}
});
},
});

module.exports = HtmlPlugin;
1 change: 1 addition & 0 deletions aws-proxy/aws_proxy/frontend/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
45 changes: 45 additions & 0 deletions aws-proxy/aws_proxy/frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "aws_proxy",
"version": "0.1.0",
"private": true,
"license": "UNLICENSED",
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@localstack/integrations": "1.2.1",
"@mui/material": "^5.15.20",
"axios": "^1.8.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.24.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.5"
},
"devDependencies": {
"@esbuild-plugins/node-modules-polyfill": "^0.1.4",
"@testing-library/react": "^13.4.0",
"@types/node": "^16.18.99",
"@types/react": "^19.1.6",
"@types/react-dom": "^17.0.11",
"concurrently": "^8.2.2",
"esbuild": "^0.16.6",
"esbuild-envfile-plugin": "^1.0.2",
"esbuild-plugin-clean": "^1.0.1",
"esbuild-plugin-copy": "^0.3.0",
"esbuild-plugin-svgr": "^1.0.0",
"live-server": "^1.2.2"
},
"scripts": {
"start": "concurrently --restart-tries -1 --raw \"yarn serve\" \"yarn watch\"",
"serve": "live-server --port=3000 --host=0.0.0.0 --no-browser --watch=aws_proxy/server/static/index.html --entry-file=index.html ../server/static",
"watch": "node .esbuild --watch",
"build": "node .esbuild"
},
"resolutions": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"@types/react-dom": "^17.0.11",
"@mui/material": "^5.15.20"
},
"packageManager": "yarn@3.2.3"
}
Binary file added aws-proxy/aws_proxy/frontend/public/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions aws-proxy/aws_proxy/frontend/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "Proxy",
"name": "Aws Proxy",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
3 changes: 3 additions & 0 deletions aws-proxy/aws_proxy/frontend/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
11 changes: 11 additions & 0 deletions aws-proxy/aws_proxy/frontend/src/CustomRoutes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ReactElement } from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import { Dashboard } from "./Dashboard";

export const CustomRoutes = (): ReactElement => (
<Routes>
{/* Make sure to always have a route fallback to "/" as it is the default page that gets opened from the web app*/}
<Route path="/" element={<Navigate replace to="/dashboard" />} />
<Route element={<Dashboard />} path="/dashboard" />
</Routes>
)
Loading
Loading