Compare commits
6 Commits
feature/do
...
67e3be028b
| Author | SHA1 | Date | |
|---|---|---|---|
| 67e3be028b | |||
| 58f93c959d | |||
| 662f720c6a | |||
| 5678e28c66 | |||
| 15c5cbaca2 | |||
| 6848baae5f |
@@ -6,7 +6,7 @@ on:
|
|||||||
target_branch:
|
target_branch:
|
||||||
description: "Branch to deploy"
|
description: "Branch to deploy"
|
||||||
required: true
|
required: true
|
||||||
default: "Dockerizing"
|
default: "main"
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -83,6 +83,10 @@ jobs:
|
|||||||
|
|
||||||
ssh "${PROD_USER}@${PROD_HOST}" "mkdir -p '${PROD_DEPLOY_PATH}'"
|
ssh "${PROD_USER}@${PROD_HOST}" "mkdir -p '${PROD_DEPLOY_PATH}'"
|
||||||
|
|
||||||
|
ssh "${PROD_USER}@${PROD_HOST}" "if [ ! -d '${PROD_DEPLOY_PATH}/.git' ]; then git clone '${PROD_GIT_URL}' '${PROD_DEPLOY_PATH}'; else cd '${PROD_DEPLOY_PATH}' && git remote set-url origin '${PROD_GIT_URL}'; fi"
|
||||||
|
|
||||||
|
ssh "${PROD_USER}@${PROD_HOST}" "cd '${PROD_DEPLOY_PATH}' && git fetch origin '${TARGET_BRANCH}' && git checkout -B '${TARGET_BRANCH}' FETCH_HEAD && git reset --hard FETCH_HEAD"
|
||||||
|
|
||||||
EFFECTIVE_BACKUP_ROOT="${PROD_BACKUP_ROOT:-/home/user/dachs_backups}"
|
EFFECTIVE_BACKUP_ROOT="${PROD_BACKUP_ROOT:-/home/user/dachs_backups}"
|
||||||
|
|
||||||
ssh "${PROD_USER}@${PROD_HOST}" "export DEPLOY_PATH='${PROD_DEPLOY_PATH}' BACKUP_ROOT='${EFFECTIVE_BACKUP_ROOT}'; sh -eu -s" <<'REMOTE_BACKUP'
|
ssh "${PROD_USER}@${PROD_HOST}" "export DEPLOY_PATH='${PROD_DEPLOY_PATH}' BACKUP_ROOT='${EFFECTIVE_BACKUP_ROOT}'; sh -eu -s" <<'REMOTE_BACKUP'
|
||||||
@@ -97,19 +101,17 @@ jobs:
|
|||||||
mkdir -p "$BACKUP_ROOT"
|
mkdir -p "$BACKUP_ROOT"
|
||||||
echo "Starting pre-deploy backup..."
|
echo "Starting pre-deploy backup..."
|
||||||
cd "$DEPLOY_PATH"
|
cd "$DEPLOY_PATH"
|
||||||
if [ -f Makefile ] && [ -f scripts/backup.sh ]; then
|
if [ -f Makefile ] && [ -f scripts/backup.sh ] && [ -f .env ]; then
|
||||||
make predeploy-backup ENV_FILE=.env BACKUP_ROOT="$BACKUP_ROOT"
|
make predeploy-backup ENV_FILE=.env BACKUP_ROOT="$BACKUP_ROOT"
|
||||||
else
|
else
|
||||||
echo "Skipping pre-deploy backup because current deployed revision does not contain backup tooling."
|
echo "Skipping pre-deploy backup because required backup files are missing in current deployment."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Skipping pre-deploy backup because no existing deployment was found."
|
echo "Skipping pre-deploy backup because no existing deployment was found."
|
||||||
fi
|
fi
|
||||||
REMOTE_BACKUP
|
REMOTE_BACKUP
|
||||||
|
|
||||||
ssh "${PROD_USER}@${PROD_HOST}" "if [ ! -d '${PROD_DEPLOY_PATH}/.git' ]; then git clone '${PROD_GIT_URL}' '${PROD_DEPLOY_PATH}'; else cd '${PROD_DEPLOY_PATH}' && git remote set-url origin '${PROD_GIT_URL}'; fi"
|
ssh "${PROD_USER}@${PROD_HOST}" "cd '${PROD_DEPLOY_PATH}' && git clean -fd"
|
||||||
|
|
||||||
ssh "${PROD_USER}@${PROD_HOST}" "cd '${PROD_DEPLOY_PATH}' && git fetch origin '${TARGET_BRANCH}' && git checkout -B '${TARGET_BRANCH}' FETCH_HEAD && git reset --hard FETCH_HEAD && git clean -fd"
|
|
||||||
|
|
||||||
ssh "${PROD_USER}@${PROD_HOST}" "cd '${PROD_DEPLOY_PATH}' && mkdir -p uploads logs/nginx"
|
ssh "${PROD_USER}@${PROD_HOST}" "cd '${PROD_DEPLOY_PATH}' && mkdir -p uploads logs/nginx"
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>한맥가족 자산관리시스템</title>
|
<title>한맥가족 자산관리시스템</title>
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
|
|||||||
@@ -28,9 +28,14 @@ has_command() {
|
|||||||
load_env() {
|
load_env() {
|
||||||
[ -f "$ENV_FILE" ] || fail "Env file not found: $ENV_FILE"
|
[ -f "$ENV_FILE" ] || fail "Env file not found: $ENV_FILE"
|
||||||
|
|
||||||
|
case "$ENV_FILE" in
|
||||||
|
*/*) env_path="$ENV_FILE" ;;
|
||||||
|
*) env_path="./$ENV_FILE" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
set -a
|
set -a
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
. "$ENV_FILE"
|
. "$env_path"
|
||||||
set +a
|
set +a
|
||||||
|
|
||||||
: "${DB_HOST:?DB_HOST is required in $ENV_FILE}"
|
: "${DB_HOST:?DB_HOST is required in $ENV_FILE}"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { state, saveAsset, deleteAsset } from '../../core/state';
|
import { state, saveAsset, deleteAsset } from '../../core/state';
|
||||||
import { ASSET_SCHEMA, UI_TEXT } from '../../core/schema';
|
import { ASSET_SCHEMA, UI_TEXT } from '../../core/schema';
|
||||||
import { calculatePcScoreDeductive, getPcGrade } from '../../core/utils';
|
import { API_BASE_URL, calculatePcScoreDeductive, getPcGrade } from '../../core/utils';
|
||||||
import {
|
import {
|
||||||
generateOptionsHTML,
|
generateOptionsHTML,
|
||||||
setFieldValue,
|
setFieldValue,
|
||||||
@@ -299,7 +299,7 @@ class HwAssetModal extends BaseModal {
|
|||||||
const prefix = TYPE_PREFIX_MAP[cat] || 'ETC';
|
const prefix = TYPE_PREFIX_MAP[cat] || 'ETC';
|
||||||
const purchaseDate = (document.getElementById('hw-purchase_date') as HTMLInputElement)?.value || '';
|
const purchaseDate = (document.getElementById('hw-purchase_date') as HTMLInputElement)?.value || '';
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://${location.hostname}:3000/api/generate-asset-code?prefix=${prefix}&purchaseDate=${purchaseDate}`);
|
const res = await fetch(`${API_BASE_URL}/api/generate-asset-code?prefix=${prefix}&purchaseDate=${purchaseDate}`);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.nextCode) setFieldValue('hw-asset_code', data.nextCode);
|
if (data.nextCode) setFieldValue('hw-asset_code', data.nextCode);
|
||||||
} catch (err) { console.error('코드 생성 실패:', err); }
|
} catch (err) { console.error('코드 생성 실패:', err); }
|
||||||
@@ -317,7 +317,7 @@ class HwAssetModal extends BaseModal {
|
|||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = async () => {
|
reader.onload = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://${location.hostname}:3000/api/upload`, {
|
const res = await fetch(`${API_BASE_URL}/api/upload`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ fileName: file.name, fileData: reader.result })
|
body: JSON.stringify({ fileName: file.name, fileData: reader.result })
|
||||||
@@ -704,7 +704,7 @@ class HwAssetModal extends BaseModal {
|
|||||||
|
|
||||||
private async fetchMapConfig() {
|
private async fetchMapConfig() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://${location.hostname}:3000/api/maps`);
|
const res = await fetch(`${API_BASE_URL}/api/maps`);
|
||||||
this.dynamicMapConfig = await res.json();
|
this.dynamicMapConfig = await res.json();
|
||||||
} catch (err) { console.error('Failed to fetch map config:', err); }
|
} catch (err) { console.error('Failed to fetch map config:', err); }
|
||||||
}
|
}
|
||||||
@@ -901,7 +901,7 @@ class HwAssetModal extends BaseModal {
|
|||||||
|
|
||||||
private async fetchMasterComponents(): Promise<void> {
|
private async fetchMasterComponents(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://${location.hostname}:3000/api/hardware-components`);
|
const res = await fetch(`${API_BASE_URL}/api/hardware-components`);
|
||||||
this.masterComponents = await res.json();
|
this.masterComponents = await res.json();
|
||||||
} catch (err) { console.error('Failed to fetch master components:', err); }
|
} catch (err) { console.error('Failed to fetch master components:', err); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,11 +196,14 @@
|
|||||||
height: auto;
|
height: auto;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
display: block;
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-overlay {
|
.map-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: auto;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-map-message {
|
.no-map-message {
|
||||||
@@ -216,6 +219,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Asset Detail Sidebar --- */
|
/* --- Asset Detail Sidebar --- */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ASSET_SCHEMA, UI_TEXT } from '../../core/schema';
|
import { ASSET_SCHEMA, UI_TEXT } from '../../core/schema';
|
||||||
import { dynamicSort, renderPageHeader, calculateAssetAge, formatInline, isWindows11Incompatible } from '../../core/utils';
|
import { API_BASE_URL, dynamicSort, renderPageHeader, calculateAssetAge, formatInline, isWindows11Incompatible } from '../../core/utils';
|
||||||
import { setupTableSorting, SortState } from '../../core/tableHandler';
|
import { setupTableSorting, SortState } from '../../core/tableHandler';
|
||||||
import { renderFilterBar, applyCommonFilters } from '../../core/filterHandler';
|
import { renderFilterBar, applyCommonFilters } from '../../core/filterHandler';
|
||||||
import { state } from '../../core/state';
|
import { state } from '../../core/state';
|
||||||
@@ -203,7 +203,7 @@ export function createListView(container: HTMLElement, config: ListViewConfig) {
|
|||||||
|
|
||||||
const fetchMapConfig = async () => {
|
const fetchMapConfig = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://${location.hostname}:3000/api/maps`);
|
const res = await fetch(`${API_BASE_URL}/api/maps`);
|
||||||
dynamicMapConfig = await res.json();
|
dynamicMapConfig = await res.json();
|
||||||
} catch (err) { console.error('Failed to fetch map config:', err); }
|
} catch (err) { console.error('Failed to fetch map config:', err); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { IMAGE_LOCATIONS } from '../components/Modal/SharedData';
|
import { IMAGE_LOCATIONS } from '../components/Modal/SharedData';
|
||||||
|
import { API_BASE_URL } from '../core/utils';
|
||||||
import { createIcons, X, Save, Trash2, ChevronLeft, ChevronRight } from 'lucide';
|
import { createIcons, X, Save, Trash2, ChevronLeft, ChevronRight } from 'lucide';
|
||||||
|
|
||||||
export class MapEditor {
|
export class MapEditor {
|
||||||
@@ -70,7 +71,7 @@ export class MapEditor {
|
|||||||
|
|
||||||
private async loadConfig() {
|
private async loadConfig() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://${location.hostname}:3000/api/maps`);
|
const res = await fetch(`${API_BASE_URL}/api/maps`);
|
||||||
this.allMapConfig = await res.json();
|
this.allMapConfig = await res.json();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to load config:', err);
|
console.error('Failed to load config:', err);
|
||||||
@@ -169,7 +170,7 @@ export class MapEditor {
|
|||||||
this.saveBtn.disabled = true;
|
this.saveBtn.disabled = true;
|
||||||
this.saveBtn.textContent = '저장 중...';
|
this.saveBtn.textContent = '저장 중...';
|
||||||
|
|
||||||
const res = await fetch(`http://${location.hostname}:3000/api/maps/save`, {
|
const res = await fetch(`${API_BASE_URL}/api/maps/save`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ path: this.currentPath, boxes: this.boxes })
|
body: JSON.stringify({ path: this.currentPath, boxes: this.boxes })
|
||||||
|
|||||||
Reference in New Issue
Block a user