pull krbl
All checks were successful
publish-main / release-image (push) Successful in 3m30s

This commit is contained in:
kuwsh1n 2024-04-15 00:38:11 +03:00
commit 209c2e0a70
9 changed files with 289 additions and 189 deletions

View File

@ -0,0 +1,56 @@
name: publish-main
on:
push
jobs:
release-image:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
env:
DOCKER_ORG: krbl
RUNNER_TOOL_CACHE: /toolcache
IMAGE_NAME: minerva-frontend
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v2
with:
config-inline: |
[registry."gitea.unprism.ru"]
- name: Login to DockerHub
uses: docker/login-action@v2
with:
registry: gitea.unprism.ru
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get Meta
id: meta
run: |
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
- name: Extract branch name
shell: bash
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
id: extract_branch
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
platforms: |
linux/amd64
linux/arm64
push: true
tags: |
gitea.unprism.ru/${{ env.DOCKER_ORG }}/${{ env.IMAGE_NAME }}:${{ steps.extract_branch.outputs.branch }}

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
dist/ dist/
node_modules/ node_modules/
package-lock.json package-lock.json
.DS_Store

12
captain-definition Normal file
View File

@ -0,0 +1,12 @@
{
"schemaVersion": 2,
"dockerfileLines": [
"FROM node",
"WORKDIR /app",
"COPY package*.json ./",
"RUN npm install",
"COPY . .",
"EXPOSE 3000",
"CMD [\"npm\", \"run\", \"start:dev\"]"
]
}

View File

@ -3,13 +3,13 @@ import { Outlet, useNavigate } from "react-router-dom";
import { FormsData, UserData, TypeAnswerData, answersData } from "./context"; import { FormsData, UserData, TypeAnswerData, answersData } from "./context";
import { useCookies } from "react-cookie"; import { useCookies } from "react-cookie";
import { globalRender } from "./router/protectedRouting.js"; import { globalRender } from "./router/protectedRouting.js";
import { verifyUserApi } from "./hooks/api/enterAccountApi.js" import { verifyUserApi } from "./hooks/api/enterAccountApi.js";
import classes from "./assets/styles/app.module.scss" import classes from "./assets/styles/app.module.scss";
import NavBar from "./components/NavBar.jsx"; import NavBar from "./components/NavBar.jsx";
import 'bootstrap/dist/css/bootstrap.min.css'; import "bootstrap/dist/css/bootstrap.min.css";
import InputText from "./components/typeAnswer/InputText.jsx"; import InputText from "./components/typeAnswer/InputText.jsx";
import TextArea from "./components/typeAnswer/TextArea.jsx"; import TextArea from "./components/typeAnswer/TextArea.jsx";
import YesNo from "./components/typeAnswer/YesNo.jsx" import YesNo from "./components/typeAnswer/YesNo.jsx";
import InputDate from "./components/typeAnswer/InputDate.jsx"; import InputDate from "./components/typeAnswer/InputDate.jsx";
import InputMultipleRadio from "./components/typeAnswer/InputMultipleRadio.jsx"; import InputMultipleRadio from "./components/typeAnswer/InputMultipleRadio.jsx";
import InputRadio from "./components/typeAnswer/InputRadio.jsx"; import InputRadio from "./components/typeAnswer/InputRadio.jsx";
@ -32,12 +32,13 @@ const App = () => {
{id: 8, text: 'Дата', typeTag: InputDate} {id: 8, text: 'Дата', typeTag: InputDate}
]); ]);
// useEffect(() => globalRender(window.location.pathname, user, navigate)); // useEffect(() => globalRender(window.location.pathname, user, navigate));
const [cookies, _, __] = useCookies(["user"]); const [cookies, _, __] = useCookies(["user"]);
useEffect(() => { useEffect(() => {
async function verifyUser() { async function verifyUser() {
const response = await verifyUserApi(cookies.token); const response = await verifyUserApi(cookies.token);
console.log("app", user);
if (response.status === 200) { if (response.status === 200) {
setUser(response.data); setUser(response.data);
@ -48,29 +49,31 @@ const App = () => {
} }
} }
verifyUser(); verifyUser();
}, []) }, []);
return ( return (
<UserData.Provider value={{ user, setUser }}> <UserData.Provider value={{ user, setUser }}>
<answersData.Provider value={{ answersList, setAnswersList }}> <answersData.Provider value={{ answersList, setAnswersList }}>
<FormsData.Provider value={{ forms, setForms }}> <FormsData.Provider value={{ forms, setForms }}>
<TypeAnswerData.Provider value={{ listTypeAnswer, setListTypeAnswer }}> <TypeAnswerData.Provider
<div className={classes.main}> value={{ listTypeAnswer, setListTypeAnswer }}
<div className={classes.container}> >
<div className={classes.header}> <div className={classes.main}>
<NavBar navigate={navigate} auth={user} setAuth={setUser}/> <div className={classes.container}>
</div> <div className={classes.header}>
<div className={classes.content}> <NavBar navigate={navigate} auth={user} setAuth={setUser} />
<Outlet/> </div>
</div> <div className={classes.content}>
</div> <Outlet />
</div> </div>
</TypeAnswerData.Provider> </div>
</FormsData.Provider> </div>
</answersData.Provider> </TypeAnswerData.Provider>
</UserData.Provider> </FormsData.Provider>
) </answersData.Provider>
} </UserData.Provider>
);
};
export default App; export default App;

View File

@ -26,7 +26,7 @@ const NavBar = ({navigate, auth, setAuth}) => {
</div> </div>
</div> </div>
</div> </div>
) );
} };
export default NavBar; export default NavBar;

View File

@ -1,14 +1,18 @@
const constructorAnswerValidate = (state, messageReject = "Ошибка", messageResolve = undefined) => { const constructorAnswerValidate = (
return state ? state,
{ messageReject = "Ошибка",
status: true, messageResolve = undefined
message: messageResolve ) => {
} : return state
{ ? {
status: false, status: true,
message: messageReject message: messageResolve,
} }
} : {
status: false,
message: messageReject,
};
};
const totalRegisterValidate = (data) => { const totalRegisterValidate = (data) => {
const listValidation = [ const listValidation = [
@ -22,12 +26,12 @@ const totalRegisterValidate = (data) => {
// constructorAnswerValidate(data.password >= 8, "Пароль должен иметь более 8 символов.") // constructorAnswerValidate(data.password >= 8, "Пароль должен иметь более 8 символов.")
] ]
for (let value of listValidation) { for (let value of listValidation) {
if (!value.status) { if (!value.status) {
return value return value;
}
} }
return { status: true } }
} return { status: true };
};
export { totalRegisterValidate, constructorAnswerValidate } export { totalRegisterValidate, constructorAnswerValidate };

View File

@ -5,19 +5,23 @@ import classes from "../assets/styles/enterAccount.module.scss";
import MyInput from "../components/MyInput.jsx"; import MyInput from "../components/MyInput.jsx";
import MyButton from "../components/MyButton.jsx"; import MyButton from "../components/MyButton.jsx";
import { UserData } from "../context"; import { UserData } from "../context";
import { logIn, completeRegistration, verifyUserApi } from "../hooks/api/enterAccountApi.js"; import {
logIn,
completeRegistration,
verifyUserApi,
} from "../hooks/api/enterAccountApi.js";
const EnterAccount = () => { const EnterAccount = () => {
const [enter, setEnter] = useState("login"); const [enter, setEnter] = useState("login");
const navigate = useNavigate(); const navigate = useNavigate();
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [phone, setPhone] = useState(""); const [phone, setPhone] = useState("");
const [login, setLogin] = useState(""); const [login, setLogin] = useState("");
const [surname, setSurname] = useState(""); const [surname, setSurname] = useState("");
const [patronymic, setPatronymic] = useState(""); const [patronymic, setPatronymic] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [repiedPassword, setRepiedPassword] = useState(""); const [repiedPassword, setRepiedPassword] = useState("");
const {user, setUser} = useContext(UserData); const {user, setUser} = useContext(UserData);
const [cookies, setCookie, removeCookie] = useCookies(["user"]); const [cookies, setCookie, removeCookie] = useCookies(["user"]);
@ -25,27 +29,27 @@ const EnterAccount = () => {
const [loginError, setLoginError] = useState(false); const [loginError, setLoginError] = useState(false);
const [regsterError, setRegsterError] = useState(false); const [regsterError, setRegsterError] = useState(false);
function cleanState() { function cleanState() {
setEmail(""); setEmail("");
setPhone(""); setPhone("");
setLogin(""); setLogin("");
setSurname(""); setSurname("");
setPatronymic(""); setPatronymic("");
setPassword(""); setPassword("");
setRepiedPassword(""); setRepiedPassword("");
}; }
function selectTag(tag) { function selectTag(tag) {
setEnter(tag); setEnter(tag);
cleanState(); cleanState();
}; }
async function createUser() { async function createUser() {
const response = await completeRegistration({ const response = await completeRegistration({
login: login, login: login,
password: password, password: password,
repiedPassword: repiedPassword repiedPassword: repiedPassword,
}); });
if (response.status === 200) { if (response.status === 200) {
const responseMe = await verifyUserApi(response.data.token) const responseMe = await verifyUserApi(response.data.token)
@ -59,8 +63,8 @@ const EnterAccount = () => {
} }
}; };
async function logInToAccount() { async function logInToAccount() {
const response = await logIn(login, password) const response = await logIn(login, password);
if (response.status === 200) { if (response.status === 200) {
setCookie("token", response.data.token); setCookie("token", response.data.token);
@ -133,14 +137,19 @@ const EnterAccount = () => {
<MyInput type={'password'} placeholder={"Повторите пароль"} otherMainStyle={{width: "100%", height: "15%"}} otherInputStyle={{width: "100%"}} value={repiedPassword} change={setRepiedPassword}/> <MyInput type={'password'} placeholder={"Повторите пароль"} otherMainStyle={{width: "100%", height: "15%"}} otherInputStyle={{width: "100%"}} value={repiedPassword} change={setRepiedPassword}/>
</div> */} </div> */}
<div className={classes.content__wrapper__register__footer}> <div className={classes.content__wrapper__register__footer}>
<MyButton text={"Создать"} otherStyle={{height: "100%", width: "20%"}} click={() => createUser()}/> <MyButton
text={"Создать"}
otherStyle={{ height: "100%", width: "20%" }}
click={() => createUser()}
/>
</div> </div>
</div>} </div>
}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
) );
} };
export default EnterAccount; export default EnterAccount;

View File

@ -1,40 +1,54 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useNavigate, useLocation, useParams } from 'react-router-dom'; import { useNavigate, useLocation, useParams } from "react-router-dom";
import classes from "../assets/styles/home.module.scss"; import classes from "../assets/styles/home.module.scss";
import MyButton from "../components/MyButton.jsx"; import MyButton from "../components/MyButton.jsx";
import MyInput from "../components/MyInput.jsx"; import MyInput from "../components/MyInput.jsx";
const Home = () => { const Home = () => {
const [token, setToken] = useState(""); const [token, setToken] = useState("");
const navigate = useNavigate(); const navigate = useNavigate();
return ( return (
<div className={classes.main}> <div className={classes.main}>
<div className={classes.wrapper}> <div className={classes.wrapper}>
<div className={classes.header}> <div className={classes.header}>
<div className={classes.header__top}>Кажется вы попали на общую страницу.</div> <div className={classes.header__top}>
<div className={classes.header__bottom}>Чтобы перейти к форме ввелите токен ниже или снова перейдите по ссылке.</div> Кажется вы попали на общую страницу.
</div> </div>
<div className={classes.content}> <div className={classes.header__bottom}>
<div className={classes.content__title}> Чтобы перейти к форме введите токен ниже или снова перейдите по
<div className={classes.content__title__wrapper}> ссылке.
<h3>Перейти к нужной форме</h3> </div>
</div>
</div>
<div className={classes.content__token}>
<div className={classes.content__token__wrapper}>
<MyInput placeholder={"Введите токен формы..."} otherMainStyle={{width: "100%"}} otherInputStyle={{width: "100%"}} value={token} change={(e) => setToken(e)}/>
</div>
</div>
<div className={classes.content__search}>
<div className={classes.content__search__wrapper}>
<MyButton text={"Найти форму"} click={() => navigate(`/forms/${token}`)}/>
</div>
</div>
</div>
</div>
</div> </div>
) <div className={classes.content}>
} <div className={classes.content__title}>
<div className={classes.content__title__wrapper}>
<h3>Перейти к нужной форме</h3>
</div>
</div>
<div className={classes.content__token}>
<div className={classes.content__token__wrapper}>
<MyInput
placeholder={"Введите токен формы..."}
otherMainStyle={{ width: "100%" }}
otherInputStyle={{ width: "100%" }}
value={token}
change={(e) => setToken(e)}
/>
</div>
</div>
<div className={classes.content__search}>
<div className={classes.content__search__wrapper}>
<MyButton
text={"Найти форму"}
click={() => navigate(`/forms/${token}`)}
/>
</div>
</div>
</div>
</div>
</div>
);
};
export default Home; export default Home;

View File

@ -1,73 +1,74 @@
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path'); const path = require("path");
module.exports = (env) => { module.exports = (env) => {
const isDev = env.mode === "development";
const isDev = env.mode === 'development'; const cssLoader = {
loader: "css-loader",
options: {
modules: {
localIdentName: isDev ? "[path][name]__[local]" : "[hash:base64:8]",
},
},
};
const cssLoader = { const config = {
loader: "css-loader", mode: env.mode ?? "development",
options: { performance: {
modules: { hints: false,
localIdentName: isDev ? '[path][name]__[local]' : '[hash:base64:8]' maxEntrypointSize: 512000,
}, maxAssetSize: 512000,
},
entry: "./src/index.js",
output: {
// filename: '[name].[contenthash].js',
filename: "bundle.js",
publicPath: "/",
path: path.resolve(__dirname, "dist"),
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public", "index.html"),
}),
isDev
? undefined
: new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:8].css",
chunkFilename: "css/[name].[contenthash:8].css",
}),
],
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [
isDev ? "style-loader" : MiniCssExtractPlugin.loader,
cssLoader,
"sass-loader",
],
}, },
} {
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
],
},
devServer: {
port: env.port ?? 3000,
historyApiFallback: true,
host: "0.0.0.0",
allowedHosts: "all",
},
};
const config = { return config;
mode: env.mode ?? 'development', };
performance: {
hints: false,
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
entry: './src/index.js',
output: {
// filename: '[name].[contenthash].js',
filename: 'bundle.js',
publicPath: '/',
path: path.resolve(__dirname, 'dist'),
clean: true
},
plugins: [
new HtmlWebpackPlugin({template: path.resolve(__dirname, 'public', 'index.html')}),
isDev ? undefined : new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].css'
})
],
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
cssLoader,
'sass-loader'
],
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
]
},
devServer: {
port: env.port ?? 3000,
open: true,
historyApiFallback: true
}
};
return config
}