Merged PR 746: ツールの雛形作成

## 概要
[Task3696: ツールの雛形作成](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3696)

- DevContainerを追加

## レビューポイント
- 特になし

## 動作確認状況
- ローカルで確認
This commit is contained in:
湯本 開 2024-02-15 05:49:45 +00:00
parent 25b7936bf4
commit cd58916e05
49 changed files with 31182 additions and 0 deletions

View File

@ -0,0 +1,32 @@
FROM node:18.13.0-buster
RUN /bin/cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
echo "Asia/Tokyo" > /etc/timezone
# Options for setup script
ARG INSTALL_ZSH="true"
ARG UPGRADE_PACKAGES="false"
ARG USERNAME=vscode
# 1000 はnodeで使われているためずらす
ARG USER_UID=1001
ARG USER_GID=$USER_UID
# Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies.
COPY library-scripts/common-debian.sh /tmp/library-scripts/
RUN bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" \
&& apt-get install default-jre -y \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts
# Install mob
RUN curl -sL install.mob.sh | sh
# 以下 ユーザー権限で実施
USER $USERNAME
# copy init-script
COPY --chown=$USERNAME:$USERNAME init.sh /home/${USERNAME}/
RUN chmod +x /home/${USERNAME}/init.sh
# 初期化を行う
# node imageのデフォルトENTRYPOINTが邪魔するため上書き
ENTRYPOINT /home/vscode/init.sh

View File

@ -0,0 +1,43 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.137.0/containers/go
{
"name": "data_migration_tools client",
"dockerComposeFile": ["./docker-compose.yml"],
"service": "client",
//
"shutdownAction": "none",
"workspaceFolder": "/app/data_migration_tools/client",
"runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"],
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true, // eslint
"source.fixAll.stylelint": true // Stylelint
},
// formatter
"editor.defaultFormatter": "esbenp.prettier-vscode", // Prettier
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.formatOnType": true,
"editor.renderWhitespace": "all",
"editor.insertSpaces": false,
"editor.renderLineHighlight": "all"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"salbert.comment-ts",
"gruntfuggly.todo-tree",
"esbenp.prettier-vscode",
"ms-vsliveshare.vsliveshare",
"albymor.increment-selection",
"eamodio.gitlens",
"wmaurer.change-case"
],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
"postCreateCommand": "sudo npm install @openapitools/openapi-generator-cli -g && sudo chown -R vscode:vscode /app/data_migration_tools/client",
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}

View File

@ -0,0 +1,20 @@
version: "3"
services:
client:
env_file: ../.env
build: .
working_dir: /app/data_migration_tools/client
ports:
- "127.0.0.1:3100:3100"
volumes:
- ../../../:/app
- data_migration_tools_client_node_modules:/app/data_migration_tools/client/node_modules
expose:
- "3100"
environment:
- CHOKIDAR_USEPOLLING=true
# Data Volume として永続化する
volumes:
data_migration_tools_client_node_modules:

View File

@ -0,0 +1,22 @@
#!/bin/bash
#
# Init Script for client Container
#
echo [init.sh] client initialize.
# /app の権限がデフォルトでは node ユーザーになっているため、
# 権限確認し、vscode ユーザでない場合付け替える
ls -ld /app | grep vscode
if [ $? -ne 0 ]; then
echo [init.sh] change /app owner to vscode.
sudo chown -R vscode:vscode /app
fi
cd /app/data_migration_tools/client
echo [init.sh] \"npm ci\" start.
npm ci
echo [init.sh] initialize completed!
sleep infinity

View File

@ -0,0 +1,190 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
# Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag]
INSTALL_ZSH=${1:-"true"}
USERNAME=${2:-"vscode"}
USER_UID=${3:-1000}
USER_GID=${4:-1000}
UPGRADE_PACKAGES=${5:-"true"}
set -e
if [ "$(id -u)" -ne 0 ]; then
echo -e 'Script must be run a root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Treat a user name of "none" as root
if [ "${USERNAME}" = "none" ] || [ "${USERNAME}" = "root" ]; then
USERNAME=root
USER_UID=0
USER_GID=0
fi
# Load markers to see which steps have already run
MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
if [ -f "${MARKER_FILE}" ]; then
echo "Marker file found:"
cat "${MARKER_FILE}"
source "${MARKER_FILE}"
fi
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
# Function to call apt-get if needed
apt-get-update-if-needed()
{
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}
# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
apt-get-update-if-needed
PACKAGE_LIST="apt-utils \
git \
openssh-client \
less \
iproute2 \
procps \
curl \
wget \
unzip \
zip \
nano \
jq \
lsb-release \
ca-certificates \
apt-transport-https \
dialog \
gnupg2 \
libc6 \
libgcc1 \
libgssapi-krb5-2 \
libicu[0-9][0-9] \
liblttng-ust0 \
libstdc++6 \
zlib1g \
locales \
sudo"
# Install libssl1.1 if available
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
PACKAGE_LIST="${PACKAGE_LIST} libssl1.1"
fi
# Install appropriate version of libssl1.0.x if available
LIBSSL=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
if [ "$(echo "$LIBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
# Debian 9
PACKAGE_LIST="${PACKAGE_LIST} libssl1.0.2"
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
# Ubuntu 18.04, 16.04, earlier
PACKAGE_LIST="${PACKAGE_LIST} libssl1.0.0"
fi
fi
echo "Packages to verify are installed: ${PACKAGE_LIST}"
apt-get -y install --no-install-recommends ${PACKAGE_LIST} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
PACKAGES_ALREADY_INSTALLED="true"
fi
# Get to latest versions of all packages
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
apt-get-update-if-needed
apt-get -y upgrade --no-install-recommends
apt-get autoremove -y
fi
# Ensure at least the en_US.UTF-8 UTF-8 locale is available.
# Common need for both applications and things like the agnoster ZSH theme.
if [ "${LOCALE_ALREADY_SET}" != "true" ]; then
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
LOCALE_ALREADY_SET="true"
fi
# Create or update a non-root user to match UID/GID - see https://aka.ms/vscode-remote/containers/non-root-user.
if id -u $USERNAME > /dev/null 2>&1; then
# User exists, update if needed
if [ "$USER_GID" != "$(id -G $USERNAME)" ]; then
groupmod --gid $USER_GID $USERNAME
usermod --gid $USER_GID $USERNAME
fi
if [ "$USER_UID" != "$(id -u $USERNAME)" ]; then
usermod --uid $USER_UID $USERNAME
fi
else
# Create user
groupadd --gid $USER_GID $USERNAME
useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME
fi
# Add add sudo support for non-root user
if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
chmod 0440 /etc/sudoers.d/$USERNAME
EXISTING_NON_ROOT_USER="${USERNAME}"
fi
# .bashrc/.zshrc snippet
RC_SNIPPET="$(cat << EOF
export USER=\$(whoami)
export PATH=\$PATH:\$HOME/.local/bin
if [[ \$(which code-insiders 2>&1) && ! \$(which code 2>&1) ]]; then
alias code=code-insiders
fi
EOF
)"
# Ensure ~/.local/bin is in the PATH for root and non-root users for bash. (zsh is later)
if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
echo "${RC_SNIPPET}" | tee -a /root/.bashrc >> /etc/skel/.bashrc
if [ "${USERNAME}" != "root" ]; then
echo "${RC_SNIPPET}" >> /home/$USERNAME/.bashrc
chown $USER_UID:$USER_GID /home/$USERNAME/.bashrc
fi
RC_SNIPPET_ALREADY_ADDED="true"
fi
# Optionally install and configure zsh
if [ "${INSTALL_ZSH}" = "true" ] && [ ! -d "/root/.oh-my-zsh" ] && [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then
apt-get-update-if-needed
apt-get install -y zsh
curl -fsSLo- https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh | bash 2>&1
echo -e "${RC_SNIPPET}\nDEFAULT_USER=\$USER\nprompt_context(){}" >> /root/.zshrc
cp -fR /root/.oh-my-zsh /etc/skel
cp -f /root/.zshrc /etc/skel
sed -i -e "s/\/root\/.oh-my-zsh/\/home\/\$(whoami)\/.oh-my-zsh/g" /etc/skel/.zshrc
if [ "${USERNAME}" != "root" ]; then
cp -fR /etc/skel/.oh-my-zsh /etc/skel/.zshrc /home/$USERNAME
chown -R $USER_UID:$USER_GID /home/$USERNAME/.oh-my-zsh /home/$USERNAME/.zshrc
fi
ZSH_ALREADY_INSTALLED="true"
fi
# Write marker file
mkdir -p "$(dirname "${MARKER_FILE}")"
echo -e "\
PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\
ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}"
echo "Done!"

View File

View File

@ -0,0 +1 @@
VITE_STAGE=local

View File

@ -0,0 +1,6 @@
node_modules/
build/
.eslintrc.js
jest.config.js
vite.config.ts
.env.local

View File

@ -0,0 +1,149 @@
module.exports = {
env: {
browser: true,
},
extends: [
"airbnb",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"prettier",
],
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json",
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: "module",
},
plugins: [
"react",
"@typescript-eslint",
"prettier",
"react-hooks",
"prefer-arrow",
],
rules: {
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off",
"react/function-component-definition": [
"error",
{
namedComponents: "arrow-function",
unnamedComponents: "arrow-function",
},
],
"react/jsx-filename-extension": [
"error",
{
extensions: ["jsx", "tsx"],
},
],
"import/extensions": [
"error",
"ignorePackages",
{
js: "never",
jsx: "never",
ts: "never",
tsx: "never",
},
],
"import/no-unresolved": "off",
"import/prefer-default-export": "off",
"no-use-before-define": 0,
"prettier/prettier": "error",
"no-param-reassign": 0,
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/prefer-interface": "off",
"@typescript-eslint/indent": "off",
"react-hooks/rules-of-hooks": "error",
// Checks rules of Hooks
"react-hooks/exhaustive-deps": "warn",
// Checks effect dependencies
"import/no-extraneous-dependencies": [
"error",
{
devDependencies: [
"**/*.test.js",
"**/*.spec.js",
"**/*.test.ts",
"**/*.spec.ts",
"**/*.test.tsx",
"**/*.spec.tsx",
"**/setupTests.ts",
],
},
],
camelcase: "off",
"prefer-arrow/prefer-arrow-functions": [
"error",
{
disallowPrototype: true,
singleReturnOnly: false,
classPropertiesAllowed: false,
},
],
"func-style": [
"error",
"expression",
{
allowArrowFunctions: true,
},
],
"react/no-multi-comp": ["error"],
"react/jsx-pascal-case": ["error"],
"@typescript-eslint/naming-convention": [
"error", // default config
{
selector: "default",
format: ["camelCase"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "variable",
format: ["camelCase", "UPPER_CASE"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "typeLike",
format: ["PascalCase"],
}, // custom config
{
selector: ["property"],
format: ["camelCase", "PascalCase"],
},
{
selector: ["variable"],
types: ["function"],
format: ["camelCase", "PascalCase"],
},
{
selector: "interface",
format: ["PascalCase"],
custom: {
regex: "^I[A-Z]",
match: false,
},
},
],
"max-lines": ["error", 3000],
},
settings: {
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx"],
},
"import/resolver": {
node: {
extensions: [".js", "jsx", ".ts", ".tsx"],
paths: ["src"],
},
},
react: {
version: "detect",
},
},
};

24
data_migration_tools/client/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.env.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.eslintcache
# credentials
credentials

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1 @@
cp -r build /app/data_migration_tools/server

14043
data_migration_tools/client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
{
"name": "client",
"private": true,
"version": "0.1.0",
"engines": {
"node": ">=18.0.0"
},
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"build:prod": "tsc && vite build",
"build:local": "tsc && vite build && sh localdeploy.sh",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"codegen": "sh codegen.sh",
"lint": "eslint --cache . --ext .js,.ts,.tsx",
"lint:fix": "npm run lint -- --fix"
},
"dependencies": {
"@azure/storage-blob": "^12.14.0",
"@reduxjs/toolkit": "^1.8.3",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.2.1",
"@types/jest": "^27.5.2",
"@types/node": "^17.0.45",
"@types/react": "^18.0.14",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"@types/redux-mock-store": "^1.0.3",
"axios": "^0.27.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"lodash": "^4.17.21",
"luxon": "^3.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-google-recaptcha-v3": "^1.10.0",
"react-paginate": "^8.1.3",
"react-redux": "^8.0.2",
"react-router-dom": "^6.4.1",
"redux-mock-store": "^1.5.4",
"redux-thunk": "^2.4.1",
"styled-components": "^5.3.5",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@babel/core": "^7.18.6",
"@mdx-js/react": "^2.1.2",
"@openapitools/openapi-generator-cli": "^2.5.2",
"@types/lodash": "^4.14.191",
"@types/luxon": "^3.2.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/redux-mock-store": "^1.0.3",
"@types/styled-components": "^5.1.25",
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.30.5",
"@vitejs/plugin-react": "^1.3.2",
"babel-loader": "^8.2.5",
"eslint": "^8.19.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"license-checker": "^25.0.1",
"prettier": "^2.7.1",
"redux-mock-store": "^1.5.4",
"typescript": "^4.7.4",
"vite": "^2.9.9",
"vite-plugin-env-compatible": "^1.1.1",
"vite-tsconfig-paths": "^3.5.0"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"overrides": [
{
"files": [
"**/*.stories.*"
],
"rules": {
"import/no-anonymous-default-export": "off"
}
}
]
}
}

View File

@ -0,0 +1,11 @@
import AppRouter from "AppRouter";
import { BrowserRouter } from "react-router-dom";
import "./styles/GlobalStyle.css";
const App = (): JSX.Element => (
<BrowserRouter>
<AppRouter />
</BrowserRouter>
);
export default App;

View File

@ -0,0 +1,9 @@
import { Route, Routes } from "react-router-dom";
const AppRouter: React.FC = () => (
<Routes>
<Route path="/" element={<div />} />
</Routes>
);
export default AppRouter;

View File

@ -0,0 +1,16 @@
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
export const store = configureStore({
reducer: {
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
export type AppDispatch = typeof store.dispatch;

View File

@ -0,0 +1,6 @@
export const getBasePath = () => {
if (import.meta.env.VITE_STAGE === "local") {
return "http://localhost:8180";
}
return window.location.origin;
};

View File

@ -0,0 +1,3 @@
export interface ErrorObject {
message: string;
}

View File

@ -0,0 +1,33 @@
.snackbar {
position: fixed;
top: -100px; /* 上から現れるための初期位置 */
left: 50%;
transform: translateX(-50%);
background-color: #323232;
color: #ffffff;
border-radius: 5px;
padding: 16px;
display: flex;
justify-content: space-between;
align-items: center;
min-width: 300px;
max-width: 80%;
z-index: 1000;
transition: top 0.5s ease-in-out; /* アニメーション効果の追加 */
}
.snackbar.show {
top: 20px; /* 最終的な表示位置 */
}
.snackbar button {
background: transparent;
border: none;
color: #ffffff;
cursor: pointer;
}
.snackbar p {
margin: 0;
margin-right: 16px;
}

View File

@ -0,0 +1,19 @@
import React, { FC } from "react";
import "./SnackBar.css";
interface SnackBarProps {
message: string;
show: boolean;
closeSnackBar: (e: React.MouseEvent<HTMLButtonElement>) => void;
}
const SnackBar: FC<SnackBarProps> = ({ message, show, closeSnackBar }) => (
<div className={`snackbar${show ? " show" : ""}`}>
<p>{message}</p>
<button type="button" onClick={closeSnackBar}>
</button>
</div>
);
export default SnackBar;

View File

@ -0,0 +1,15 @@
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
<stop stop-color="#41D1FF"/>
<stop offset="1" stop-color="#BD34FE"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA83"/>
<stop offset="0.0833333" stop-color="#FFDD35"/>
<stop offset="1" stop-color="#FFA800"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,23 @@
import { store } from "app/store";
import React from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
const container = document.getElementById("root");
if (container) {
const root = createRoot(container);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
}
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

View File

@ -0,0 +1,148 @@
/* eslint-disable */
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === "localhost" ||
// [::1] is the IPv6 localhost address.
window.location.hostname === "[::1]" ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
type Config = {
onSuccess?: (registration: ServiceWorkerRegistration) => void;
onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
export function register(config?: Config) {
if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener("load", () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
"This web app is being served cache-first by a service " +
"worker. To learn more, visit https://bit.ly/CRA-PWA"
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === "installed") {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
"New content is available and will be used when all " +
"tabs for this page are closed. See https://bit.ly/CRA-PWA."
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log("Content is cached for offline use.");
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch((error) => {
console.error("Error during service worker registration:", error);
});
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { "Service-Worker": "script" },
})
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get("content-type");
if (
response.status === 404 ||
(contentType != null && contentType.indexOf("javascript") === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
"No internet connection found. App is running in offline mode."
);
});
}
export function unregister() {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready
.then((registration) => {
registration.unregister();
})
.catch((error) => {
console.error(error.message);
});
}
}

View File

@ -0,0 +1,37 @@
/**
* bring from react-scripts/lib/react-app.d.ts
*/
declare namespace NodeJS {
interface ProcessEnv {
/* eslint-disable @typescript-eslint/naming-convention */
// local環境はdevelopment、staging環境は production になる
readonly NODE_ENV: "development" | "develop" | "production" | "test";
readonly PUBLIC_URL: string;
/* eslint-enable @typescript-eslint/naming-convention */
}
}
declare module "*.gif" {
const src: string;
export default src;
}
declare module "*.jpg" {
const src: string;
export default src;
}
declare module "*.jpeg" {
const src: string;
export default src;
}
declare module "*.png" {
const src: string;
export default src;
}
declare module "*.svg" {
const src: string;
export default src;
}

View File

@ -0,0 +1,11 @@
/* eslint-disable @typescript-eslint/naming-convention */
// 環境変数のコード補完
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_STAGE: string;
readonly VITE_ODMS_CLOUD_BASE_PATH: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es2019",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"baseUrl": "src",
"plugins": [{ "name": "typescript-styled-plugin" }]
},
"include": ["src"]
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import env from "vite-plugin-env-compatible";
export default defineConfig({
server: {
host: true,
port: 3100,
open: true,
},
build: {
outDir: "build",
sourcemap: true,
minify: false,
},
plugins: [env(), tsconfigPaths(), react()],
});

View File

@ -0,0 +1,31 @@
FROM node:18.13.0-buster
RUN /bin/cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
echo "Asia/Tokyo" > /etc/timezone
# Options for setup script
ARG INSTALL_ZSH="true"
ARG UPGRADE_PACKAGES="false"
ARG USERNAME=vscode
# 1000 はnodeで使われているためずらす
ARG USER_UID=1001
ARG USER_GID=$USER_UID
# Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies.
COPY library-scripts/common-debian.sh /tmp/library-scripts/
RUN bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" \
&& apt-get install default-jre -y \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts
# Install NestJS
RUN npm i -g @nestjs/cli
# 以下 ユーザー権限で実施
USER $USERNAME
# copy init-script
COPY --chown=$USERNAME:$USERNAME init.sh /home/${USERNAME}/
RUN chmod +x /home/${USERNAME}/init.sh
# 初期化を行う
# node imageのデフォルトENTRYPOINTが邪魔するため上書き
ENTRYPOINT /home/vscode/init.sh

View File

@ -0,0 +1,56 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/javascript-node
{
"name": "data_migration_tools server",
"dockerComposeFile": [
"./docker-compose.yml"
],
"service": "server",
//
"shutdownAction": "none",
"workspaceFolder": "/app/data_migration_tools/server",
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.format.enable": false,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// formatter
"editor.formatOnPaste": true,
"editor.formatOnType": true,
"editor.renderWhitespace": "all",
"editor.insertSpaces": false,
"editor.renderLineHighlight": "all"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"salbert.comment-ts",
"gruntfuggly.todo-tree",
"esbenp.prettier-vscode",
"ms-vsliveshare.vsliveshare",
"albymor.increment-selection",
"eamodio.gitlens",
"wmaurer.change-case"
],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
"postCreateCommand": "sudo chown -R vscode:vscode /app/data_migration_tools/server",
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}

View File

@ -0,0 +1,18 @@
version: "3"
services:
server:
env_file: ../.env
build: .
working_dir: /app/data_migration_tools/server
ports:
- "127.0.0.1:8280:8280"
volumes:
- ../../../:/app
- data_migration_tools_server_node_modules:/app/data_migration_tools/server/node_modules
expose:
- "8280"
environment:
- CHOKIDAR_USEPOLLING=true
volumes:
data_migration_tools_server_node_modules:

View File

@ -0,0 +1,20 @@
#!/bin/bash
#
# Init Script for server Container
#
echo [init.sh] server initialize.
# /app の権限がデフォルトでは node ユーザーになっているため、
# 権限確認し、vscode ユーザでない場合付け替える
ls -ld /app | grep vscode
if [ $? -ne 0 ]; then
echo [init.sh] change /app owner to vscode.
sudo chown -R vscode:vscode /app
fi
cd /app/server
echo [init.sh] initialize completed!
sleep infinity

View File

@ -0,0 +1,190 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
# Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag]
INSTALL_ZSH=${1:-"true"}
USERNAME=${2:-"vscode"}
USER_UID=${3:-1000}
USER_GID=${4:-1000}
UPGRADE_PACKAGES=${5:-"true"}
set -e
if [ "$(id -u)" -ne 0 ]; then
echo -e 'Script must be run a root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Treat a user name of "none" as root
if [ "${USERNAME}" = "none" ] || [ "${USERNAME}" = "root" ]; then
USERNAME=root
USER_UID=0
USER_GID=0
fi
# Load markers to see which steps have already run
MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
if [ -f "${MARKER_FILE}" ]; then
echo "Marker file found:"
cat "${MARKER_FILE}"
source "${MARKER_FILE}"
fi
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
# Function to call apt-get if needed
apt-get-update-if-needed()
{
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}
# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
apt-get-update-if-needed
PACKAGE_LIST="apt-utils \
git \
openssh-client \
less \
iproute2 \
procps \
curl \
wget \
unzip \
zip \
nano \
jq \
lsb-release \
ca-certificates \
apt-transport-https \
dialog \
gnupg2 \
libc6 \
libgcc1 \
libgssapi-krb5-2 \
libicu[0-9][0-9] \
liblttng-ust0 \
libstdc++6 \
zlib1g \
locales \
sudo"
# Install libssl1.1 if available
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
PACKAGE_LIST="${PACKAGE_LIST} libssl1.1"
fi
# Install appropriate version of libssl1.0.x if available
LIBSSL=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
if [ "$(echo "$LIBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
# Debian 9
PACKAGE_LIST="${PACKAGE_LIST} libssl1.0.2"
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
# Ubuntu 18.04, 16.04, earlier
PACKAGE_LIST="${PACKAGE_LIST} libssl1.0.0"
fi
fi
echo "Packages to verify are installed: ${PACKAGE_LIST}"
apt-get -y install --no-install-recommends ${PACKAGE_LIST} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
PACKAGES_ALREADY_INSTALLED="true"
fi
# Get to latest versions of all packages
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
apt-get-update-if-needed
apt-get -y upgrade --no-install-recommends
apt-get autoremove -y
fi
# Ensure at least the en_US.UTF-8 UTF-8 locale is available.
# Common need for both applications and things like the agnoster ZSH theme.
if [ "${LOCALE_ALREADY_SET}" != "true" ]; then
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
LOCALE_ALREADY_SET="true"
fi
# Create or update a non-root user to match UID/GID - see https://aka.ms/vscode-remote/containers/non-root-user.
if id -u $USERNAME > /dev/null 2>&1; then
# User exists, update if needed
if [ "$USER_GID" != "$(id -G $USERNAME)" ]; then
groupmod --gid $USER_GID $USERNAME
usermod --gid $USER_GID $USERNAME
fi
if [ "$USER_UID" != "$(id -u $USERNAME)" ]; then
usermod --uid $USER_UID $USERNAME
fi
else
# Create user
groupadd --gid $USER_GID $USERNAME
useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME
fi
# Add add sudo support for non-root user
if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
chmod 0440 /etc/sudoers.d/$USERNAME
EXISTING_NON_ROOT_USER="${USERNAME}"
fi
# .bashrc/.zshrc snippet
RC_SNIPPET="$(cat << EOF
export USER=\$(whoami)
export PATH=\$PATH:\$HOME/.local/bin
if [[ \$(which code-insiders 2>&1) && ! \$(which code 2>&1) ]]; then
alias code=code-insiders
fi
EOF
)"
# Ensure ~/.local/bin is in the PATH for root and non-root users for bash. (zsh is later)
if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
echo "${RC_SNIPPET}" | tee -a /root/.bashrc >> /etc/skel/.bashrc
if [ "${USERNAME}" != "root" ]; then
echo "${RC_SNIPPET}" >> /home/$USERNAME/.bashrc
chown $USER_UID:$USER_GID /home/$USERNAME/.bashrc
fi
RC_SNIPPET_ALREADY_ADDED="true"
fi
# Optionally install and configure zsh
if [ "${INSTALL_ZSH}" = "true" ] && [ ! -d "/root/.oh-my-zsh" ] && [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then
apt-get-update-if-needed
apt-get install -y zsh
curl -fsSLo- https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh | bash 2>&1
echo -e "${RC_SNIPPET}\nDEFAULT_USER=\$USER\nprompt_context(){}" >> /root/.zshrc
cp -fR /root/.oh-my-zsh /etc/skel
cp -f /root/.zshrc /etc/skel
sed -i -e "s/\/root\/.oh-my-zsh/\/home\/\$(whoami)\/.oh-my-zsh/g" /etc/skel/.zshrc
if [ "${USERNAME}" != "root" ]; then
cp -fR /etc/skel/.oh-my-zsh /etc/skel/.zshrc /home/$USERNAME
chown -R $USER_UID:$USER_GID /home/$USERNAME/.oh-my-zsh /home/$USERNAME/.zshrc
fi
ZSH_ALREADY_INSTALLED="true"
fi
# Write marker file
mkdir -p "$(dirname "${MARKER_FILE}")"
echo -e "\
PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\
ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}"
echo "Done!"

View File

View File

@ -0,0 +1,25 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir : __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};

View File

@ -0,0 +1,8 @@
/dist*
/node_modules
/dump.rdb
/build
/openapi/build
.env.local

View File

@ -0,0 +1,14 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start:debug"],
"envFile": "${workspaceFolder}/.env",
"console": "integratedTerminal"
}
]
}

View File

@ -0,0 +1,21 @@
{
"terminal.integrated.shell.linux": "/bin/bash",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.format.enable": false,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.formatOnPaste": true,
"editor.formatOnType": true,
"editor.renderWhitespace": "all",
"editor.insertSpaces": false,
"editor.renderLineHighlight": "all"
}

View File

@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src"
}

15586
data_migration_tools/server/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
{
"name": "data_migration_tool",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build && cp -r build dist",
"build:exe": "nest build && cp -r build dist && sh ./buildTool.sh",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
"lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand"
},
"dependencies": {
"@azure/storage-blob": "^12.14.0",
"@nestjs/common": "^9.3.9",
"@nestjs/config": "^2.3.1",
"@nestjs/core": "^9.3.9",
"@nestjs/platform-express": "^9.4.1",
"@nestjs/serve-static": "^3.0.1",
"@nestjs/swagger": "^6.2.1",
"@nestjs/testing": "^9.3.9",
"@openapitools/openapi-generator-cli": "^2.5.2",
"@vercel/ncc": "^0.36.1",
"axios": "^1.3.4",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"cookie-parser": "^1.4.6",
"multer": "^1.4.5-lts.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.0",
"swagger-cli": "^4.0.4"
},
"devDependencies": {
"@types/express": "^4.17.17",
"@types/multer": "^1.4.7",
"@types/node": "^20.2.3",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "28.0.3",
"license-checker": "^25.0.1",
"prettier": "^2.3.2",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"swagger-ui-express": "^4.5.0",
"ts-jest": "28.0.1",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.0.0",
"typescript": "^4.3.5"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}

View File

@ -0,0 +1,24 @@
import { MiddlewareConsumer, Module } from "@nestjs/common";
import { ServeStaticModule } from "@nestjs/serve-static";
import { ConfigModule } from "@nestjs/config";
import { join } from "path";
import { LoggerMiddleware } from "./common/loggerMiddleware";
@Module({
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, ".", "build"),
}),
ConfigModule.forRoot({
envFilePath: [".env.local", ".env"],
isGlobal: true,
}),
],
controllers: [],
providers: [],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes("");
}
}

View File

@ -0,0 +1,6 @@
import { AxiosError } from "axios";
export const isAxiosError = (e: unknown): e is AxiosError => {
const error = e as AxiosError;
return error?.isAxiosError ?? false;
};

View File

@ -0,0 +1,28 @@
import { Injectable, Logger, NestMiddleware } from "@nestjs/common";
import { Request, Response } from "express";
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
private readonly logger = new Logger(LoggerMiddleware.name);
use(req: Request, res: Response, next: () => void): void {
this.logger.log(this.createReqMsg(req));
res.on("close", () => {
this.logger.log(this.createResMsg(res));
});
next();
}
private createReqMsg(req: Request): string {
const message = `Request [url=${req.url}, method=${req.method}]`;
return message;
}
private createResMsg(res: Response): string {
const message = `Response [statusCode=${res.statusCode}, message=${res.statusMessage}]`;
return message;
}
}

View File

@ -0,0 +1,35 @@
import { NestFactory } from "@nestjs/core";
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import { AppModule } from "./app.module";
import { ValidationPipe } from "@nestjs/common";
import { LoggerMiddleware } from "./common/loggerMiddleware";
import cookieParser from "cookie-parser";
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
cors: process.env.CORS === "TRUE",
});
app.use(new LoggerMiddleware(), cookieParser());
// バリデーター(+型の自動変換機能)を適用
app.useGlobalPipes(
new ValidationPipe({ transform: true, forbidUnknownValues: false })
);
if (process.env.STAGE === "local") {
const options = new DocumentBuilder()
.setTitle("data_migration_toolsOpenAPI")
.setVersion("1.0.0")
.addBearerAuth({
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
})
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup("api", app, document);
}
await app.listen(process.env.PORT || 8180);
}
bootstrap();

View File

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}

View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2022",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false,
"esModuleInterop": true
}
}