vite preview mode
This commit is contained in:
39
.dockerignore
Normal file
39
.dockerignore
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
viewer/node_modules
|
||||||
|
|
||||||
|
# Build output
|
||||||
|
viewer/dist
|
||||||
|
viewer/build
|
||||||
|
|
||||||
|
# IDE / Editor specific
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
# Local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
28
Dockerfile
Normal file
28
Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Use a lightweight Node.js image
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Set the working directory inside the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package.json and lock files from the viewer directory first
|
||||||
|
# to leverage Docker layer caching
|
||||||
|
COPY viewer/package.json viewer/pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# Install pnpm globally
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Install all dependencies (including devDependencies for Vite)
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy the rest of the application source code from the viewer directory
|
||||||
|
COPY viewer/ ./
|
||||||
|
|
||||||
|
# Build the application for production
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# Expose the port Vite preview will run on
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# The command to run the app using Vite's preview server
|
||||||
|
# --host 0.0.0.0 is crucial to make the server accessible from outside the container
|
||||||
|
CMD ["pnpm", "exec", "vite", "preview", "--host", "0.0.0.0", "--port", "3000"]
|
||||||
10
docker-compose.yml
Normal file
10
docker-compose.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
qna-viewer:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: qna-viewer:latest
|
||||||
|
container_name: qna-viewer-app
|
||||||
|
ports:
|
||||||
|
- "8073:3000"
|
||||||
|
restart: unless-stopped
|
||||||
@@ -15,6 +15,7 @@ VITE_DESCOPE_PROJECT_ID=P2wON5fy1K6kyia269VpeIzYP8oP
|
|||||||
VITE_DESCOPE_FLOW_ID=sign-up-with-password-standard
|
VITE_DESCOPE_FLOW_ID=sign-up-with-password-standard
|
||||||
|
|
||||||
VITE_DESCOPE_USER_PROFILE_WIDGET_ID=user-profile-widget-standard
|
VITE_DESCOPE_USER_PROFILE_WIDGET_ID=user-profile-widget-standard
|
||||||
|
|
||||||
# Descope base URL
|
# Descope base URL
|
||||||
DESCOPE_BASE_URL=""
|
DESCOPE_BASE_URL=""
|
||||||
# Descope base static URL
|
# Descope base static URL
|
||||||
|
|||||||
@@ -59,9 +59,10 @@ export function DynamicForm({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderField = (field: FeedbackField) => {
|
const renderField = (field: FeedbackField) => {
|
||||||
|
const value = String(formData[field.id] ?? "");
|
||||||
const commonProps = {
|
const commonProps = {
|
||||||
id: field.id,
|
id: field.id,
|
||||||
value: formData[field.id] ?? "",
|
value: value,
|
||||||
disabled: field.readOnly,
|
disabled: field.readOnly,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -375,8 +375,8 @@ export function DynamicTable<TData extends BaseData>({
|
|||||||
<div
|
<div
|
||||||
role="slider"
|
role="slider"
|
||||||
aria-label={`컬럼 너비 조절: ${header.id}`}
|
aria-label={`컬럼 너비 조절: ${header.id}`}
|
||||||
aria-valuemin={header.column.minSize}
|
aria-valuemin={header.column.columnDef.minSize}
|
||||||
aria-valuemax={header.column.maxSize}
|
aria-valuemax={header.column.columnDef.maxSize}
|
||||||
aria-valuenow={header.column.getSize()}
|
aria-valuenow={header.column.getSize()}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onMouseDown={header.getResizeHandler()}
|
onMouseDown={header.getResizeHandler()}
|
||||||
|
|||||||
@@ -50,8 +50,6 @@ export function Header() {
|
|||||||
return `/projects/${projectId}/channels/${channelId}${basePath}`;
|
return `/projects/${projectId}/channels/${channelId}${basePath}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const homePath = projectId ? `/projects/${projectId}` : "/";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="border-b">
|
<header className="border-b">
|
||||||
<div className="container mx-auto flex h-16 items-center">
|
<div className="container mx-auto flex h-16 items-center">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
|||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<AuthProvider projectId={projectId}>
|
<AuthProvider projectId={projectId}>
|
||||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
<ThemeProvider>
|
||||||
<App />
|
<App />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
|
|||||||
@@ -51,13 +51,13 @@ export function FeedbackListPage() {
|
|||||||
fetchSchemaAndFeedbacks();
|
fetchSchemaAndFeedbacks();
|
||||||
}, [projectId, channelId]);
|
}, [projectId, channelId]);
|
||||||
|
|
||||||
const handleRowClick = (row: Feedback) => {
|
const handleRowClick = (row: any) => {
|
||||||
navigate(
|
navigate(
|
||||||
`/projects/${projectId}/channels/${channelId}/feedbacks/${row.id}`,
|
`/projects/${projectId}/channels/${channelId}/feedbacks/${row.id}`,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderExpandedRow = (row: Row<Feedback>) => (
|
const renderExpandedRow = (row: Row<any>) => (
|
||||||
<div className="p-4 bg-muted rounded-md">
|
<div className="p-4 bg-muted rounded-md">
|
||||||
<h4 className="font-bold text-lg mb-2">{row.original.title}</h4>
|
<h4 className="font-bold text-lg mb-2">{row.original.title}</h4>
|
||||||
<p className="whitespace-pre-wrap">{row.original.contents}</p>
|
<p className="whitespace-pre-wrap">{row.original.contents}</p>
|
||||||
@@ -68,6 +68,11 @@ export function FeedbackListPage() {
|
|||||||
return <div className="text-center py-10">로딩 중...</div>;
|
return <div className="text-center py-10">로딩 중...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tableData = feedbacks.map(item => ({
|
||||||
|
...item,
|
||||||
|
updatedAt: item.updatedAt || new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
title="피드백 목록"
|
title="피드백 목록"
|
||||||
@@ -84,7 +89,7 @@ export function FeedbackListPage() {
|
|||||||
{schema && (
|
{schema && (
|
||||||
<DynamicTable
|
<DynamicTable
|
||||||
columns={schema}
|
columns={schema}
|
||||||
data={feedbacks}
|
data={tableData}
|
||||||
onRowClick={handleRowClick}
|
onRowClick={handleRowClick}
|
||||||
renderExpandedRow={renderExpandedRow}
|
renderExpandedRow={renderExpandedRow}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
|||||||
Reference in New Issue
Block a user