mirror of
https://github.com/morbalint/kemkas.git
synced 2026-07-17 19:03:46 +00:00
add save button and remove asp.net SPA proxy
using the docker compose nginx proxy instead
This commit is contained in:
@@ -24,12 +24,12 @@ public class CharacterDbModelToDtoService : ICharacterDbModelToDtoService
|
|||||||
Osztaly = entity.Osztaly.Convert(),
|
Osztaly = entity.Osztaly.Convert(),
|
||||||
Tulajdonsagok = new KarakterTulajdonsagokDto
|
Tulajdonsagok = new KarakterTulajdonsagokDto
|
||||||
{
|
{
|
||||||
T_Ero = entity.Ero,
|
Ero = entity.Ero,
|
||||||
T_Ugy = entity.Ugyesseg,
|
Ugy = entity.Ugyesseg,
|
||||||
T_Egs = entity.Egeszseg,
|
Egs = entity.Egeszseg,
|
||||||
T_Int = entity.Intelligencia,
|
Int = entity.Intelligencia,
|
||||||
T_Bol = entity.Bolcsesseg,
|
Bol = entity.Bolcsesseg,
|
||||||
T_Kar = entity.Karizma,
|
Kar = entity.Karizma,
|
||||||
},
|
},
|
||||||
Kepzettsegek = entity.KarakterKepzettsegek.Where(x => !x.IsTolvajKepzettseg).Select(x => x.Kepzettseg.Convert()).ToList(),
|
Kepzettsegek = entity.KarakterKepzettsegek.Where(x => !x.IsTolvajKepzettseg).Select(x => x.Kepzettseg.Convert()).ToList(),
|
||||||
Tolvajkepzettsegek = entity.KarakterKepzettsegek.Where(x => x.IsTolvajKepzettseg).Select(x => x.Kepzettseg.Convert()).ToList(),
|
Tolvajkepzettsegek = entity.KarakterKepzettsegek.Where(x => x.IsTolvajKepzettseg).Select(x => x.Kepzettseg.Convert()).ToList(),
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ public class CharacterDtoToDbModelService : ICharacterDtoToDbModelService
|
|||||||
Isten = dto.Isten,
|
Isten = dto.Isten,
|
||||||
Faj = FajExtensions.Convert(dto.Faj),
|
Faj = FajExtensions.Convert(dto.Faj),
|
||||||
Osztaly = OsztalyExtensions.Convert(dto.Osztaly),
|
Osztaly = OsztalyExtensions.Convert(dto.Osztaly),
|
||||||
Ero = dto.Tulajdonsagok.T_Ero,
|
Ero = dto.Tulajdonsagok.Ero,
|
||||||
Ugyesseg = dto.Tulajdonsagok.T_Ugy,
|
Ugyesseg = dto.Tulajdonsagok.Ugy,
|
||||||
Egeszseg = dto.Tulajdonsagok.T_Egs,
|
Egeszseg = dto.Tulajdonsagok.Egs,
|
||||||
Intelligencia = dto.Tulajdonsagok.T_Int,
|
Intelligencia = dto.Tulajdonsagok.Int,
|
||||||
Bolcsesseg = dto.Tulajdonsagok.T_Bol,
|
Bolcsesseg = dto.Tulajdonsagok.Bol,
|
||||||
Karizma = dto.Tulajdonsagok.T_Kar,
|
Karizma = dto.Tulajdonsagok.Kar,
|
||||||
Szint = dto.Szint,
|
Szint = dto.Szint,
|
||||||
};
|
};
|
||||||
karakter.KarakterKepzettsegek = ConvertKepzettsegek(dto, karakter);
|
karakter.KarakterKepzettsegek = ConvertKepzettsegek(dto, karakter);
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Kemkas.Web.ViewModels;
|
namespace Kemkas.Web.ViewModels;
|
||||||
|
|
||||||
public struct KarakterTulajdonsagokDto
|
public struct KarakterTulajdonsagokDto
|
||||||
{
|
{
|
||||||
public byte T_Ero { get; set; }
|
[JsonPropertyName("t_ero")]
|
||||||
public byte T_Ugy { get; set; }
|
public byte Ero { get; set; }
|
||||||
public byte T_Egs { get; set; }
|
[JsonPropertyName("t_ugy")]
|
||||||
public byte T_Int { get; set; }
|
public byte Ugy { get; set; }
|
||||||
public byte T_Bol { get; set; }
|
[JsonPropertyName("t_egs")]
|
||||||
public byte T_Kar { get; set; }
|
public byte Egs { get; set; }
|
||||||
|
[JsonPropertyName("t_int")]
|
||||||
|
public byte Int { get; set; }
|
||||||
|
[JsonPropertyName("t_bol")]
|
||||||
|
public byte Bol { get; set; }
|
||||||
|
[JsonPropertyName("t_kar")]
|
||||||
|
public byte Kar { get; set; }
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,11 @@ function App(props: {faro?: Faro}) {
|
|||||||
path: "/",
|
path: "/",
|
||||||
element: <CreateCharacter faro={props.faro} />,
|
element: <CreateCharacter faro={props.faro} />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/:id",
|
||||||
|
element: <CreateCharacter faro={props.faro} />,
|
||||||
|
loader: args => fetch(`/Character/${args.params.id}`)
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import {Tooltip} from "react-bootstrap";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const SaveOverlayTooltip = <Tooltip id="save-tooltip">
|
||||||
|
A mentéssel egyedi URL-en elérhető lesz a karakter bárkinek, azonban módosítani már nem lehet, csak újat menteni.
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
export default SaveOverlayTooltip
|
||||||
@@ -17,23 +17,29 @@ import {
|
|||||||
SetDefaultTolvajKepzettsegek,
|
SetDefaultTolvajKepzettsegek,
|
||||||
} from "../domain-models/kepzettsegek";
|
} from "../domain-models/kepzettsegek";
|
||||||
import {CreatePDF} from "../pdf/character.pdf";
|
import {CreatePDF} from "../pdf/character.pdf";
|
||||||
import {KarakterDefaults} from "../domain-models/karakter";
|
import {KarakterDefaults, KarakterInputs} from "../domain-models/karakter";
|
||||||
import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
|
import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
|
||||||
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
|
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
|
||||||
import JellemSelector from "../components/JellemSelector";
|
import JellemSelector from "../components/JellemSelector";
|
||||||
import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level";
|
import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level";
|
||||||
import {Card} from "react-bootstrap";
|
import {Card, OverlayTrigger} from "react-bootstrap";
|
||||||
import LevelUps from "../components/LevelUps";
|
import LevelUps from "../components/LevelUps";
|
||||||
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio";
|
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio";
|
||||||
import Felszereles from '../components/Felszereles';
|
import Felszereles from '../components/Felszereles';
|
||||||
import { KarakterFelszereles } from '../domain-models/felszereles';
|
import { KarakterFelszereles } from '../domain-models/felszereles';
|
||||||
import {Faro} from "@grafana/faro-web-sdk";
|
import {Faro} from "@grafana/faro-web-sdk";
|
||||||
import {StoreNewCharacter} from "../api/character.api";
|
import {StoreNewCharacter} from "../api/character.api";
|
||||||
|
import {useLoaderData} from "react-router-dom";
|
||||||
|
import saveOverlayTooltip from "../components/SaveOverlayTooltip";
|
||||||
|
|
||||||
function CreateCharacterPage(props: {faro?: Faro}) {
|
function CreateCharacterPage(props: {
|
||||||
|
faro?: Faro,
|
||||||
|
}) {
|
||||||
const {faro} = props
|
const {faro} = props
|
||||||
|
|
||||||
let [karakter, changeKarakter] = useState(KarakterDefaults)
|
const initialKarakterInputs = useLoaderData() as KarakterInputs;
|
||||||
|
|
||||||
|
let [karakter, changeKarakter] = useState(initialKarakterInputs ?? KarakterDefaults)
|
||||||
|
|
||||||
const tulajdonsagokFajjal = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
|
const tulajdonsagokFajjal = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
|
||||||
|
|
||||||
@@ -50,7 +56,6 @@ function CreateCharacterPage(props: {faro?: Faro}) {
|
|||||||
|
|
||||||
const canLevelUp = CanLevelUp(karakter)
|
const canLevelUp = CanLevelUp(karakter)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='container-fluid p-5 bg-black text-white text-center'>
|
<div className='container-fluid p-5 bg-black text-white text-center'>
|
||||||
@@ -167,11 +172,27 @@ function CreateCharacterPage(props: {faro?: Faro}) {
|
|||||||
<Felszereles osztaly={karakter.osztaly} felszereles={karakter.felszereles}
|
<Felszereles osztaly={karakter.osztaly} felszereles={karakter.felszereles}
|
||||||
changeFelszereles={setFelszereles} harcosSpec={karakter.harcosSpecializaciok}/>
|
changeFelszereles={setFelszereles} harcosSpec={karakter.harcosSpecializaciok}/>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-6">
|
||||||
<div className='d-grid gap-2 m-5'>
|
<div className='d-grid gap-2 m-5'>
|
||||||
|
<OverlayTrigger placement='top' overlay={saveOverlayTooltip} delay={0} defaultShow={false} flip={false}>
|
||||||
<button className='btn btn-danger btn-lg' type='button' onClick={async () => {
|
<button className='btn btn-danger btn-lg' type='button' onClick={async () => {
|
||||||
await StoreNewCharacter(karakter)
|
faro?.api.pushEvent('public_character_stored', {
|
||||||
|
osztaly: karakter.osztaly,
|
||||||
|
szint: karakter.szint.toString()
|
||||||
|
})
|
||||||
|
let newId = await StoreNewCharacter(karakter)
|
||||||
|
const win = window.open(`/${newId}`, '_blank');
|
||||||
|
if (win != null) {
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
}}>Mentés
|
}}>Mentés
|
||||||
</button>
|
</button>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-6">
|
||||||
|
<div className='d-grid gap-2 m-5'>
|
||||||
<button className='btn btn-danger btn-lg' type='button' onClick={async () => {
|
<button className='btn btn-danger btn-lg' type='button' onClick={async () => {
|
||||||
faro?.api.pushEvent('character_created', {
|
faro?.api.pushEvent('character_created', {
|
||||||
osztaly: karakter.osztaly,
|
osztaly: karakter.osztaly,
|
||||||
@@ -181,6 +202,8 @@ function CreateCharacterPage(props: {faro?: Faro}) {
|
|||||||
}}>PDF
|
}}>PDF
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
|
||||||
const { env } = require('process');
|
|
||||||
|
|
||||||
const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
|
|
||||||
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:40870';
|
|
||||||
|
|
||||||
const context = [
|
|
||||||
"/weatherforecast",
|
|
||||||
"/_configuration",
|
|
||||||
"/.well-known",
|
|
||||||
"/Identity",
|
|
||||||
"/connect",
|
|
||||||
"/ApplyDatabaseMigrations",
|
|
||||||
"/_framework"
|
|
||||||
];
|
|
||||||
|
|
||||||
const onError = (err, req, resp, target) => {
|
|
||||||
console.error(`${err.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = function (app) {
|
|
||||||
const appProxy = createProxyMiddleware(context, {
|
|
||||||
target: target,
|
|
||||||
// Handle errors to prevent the proxy middleware from crashing when
|
|
||||||
// the ASP NET Core webserver is unavailable
|
|
||||||
onError: onError,
|
|
||||||
secure: false,
|
|
||||||
// Uncomment this line to add support for proxying websockets
|
|
||||||
//ws: true,
|
|
||||||
headers: {
|
|
||||||
Connection: 'Keep-Alive'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(appProxy);
|
|
||||||
};
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
|
||||||
// allows you to do things like:
|
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
|
||||||
import '@testing-library/jest-dom';
|
|
||||||
|
|
||||||
const localStorageMock = {
|
|
||||||
getItem: jest.fn(),
|
|
||||||
setItem: jest.fn(),
|
|
||||||
removeItem: jest.fn(),
|
|
||||||
clear: jest.fn(),
|
|
||||||
length: 0,
|
|
||||||
key: jest.fn()
|
|
||||||
};
|
|
||||||
global.localStorage = localStorageMock;
|
|
||||||
|
|
||||||
// Mock the request issued by the react app to get the client configuration parameters.
|
|
||||||
window.fetch = () => {
|
|
||||||
return Promise.resolve(
|
|
||||||
{
|
|
||||||
ok: true,
|
|
||||||
json: () => Promise.resolve({
|
|
||||||
"authority": "https://localhost:7251",
|
|
||||||
"client_id": "Kemkas.Web",
|
|
||||||
"redirect_uri": "https://localhost:7251/authentication/login-callback",
|
|
||||||
"post_logout_redirect_uri": "https://localhost:7251/authentication/logout-callback",
|
|
||||||
"response_type": "id_token token",
|
|
||||||
"scope": "Kemkas.WebAPI openid profile"
|
|
||||||
})
|
|
||||||
});
|
|
||||||
};
|
|
||||||
+11
@@ -2,6 +2,17 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kemkas.Web", "Kemkas.Web\Kemkas.Web.csproj", "{ABAEE4DC-1A07-40AE-A2B6-4D3755A6C1E8}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kemkas.Web", "Kemkas.Web\Kemkas.Web.csproj", "{ABAEE4DC-1A07-40AE-A2B6-4D3755A6C1E8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "General", "General", "{5D06CE1E-DD86-41C0-A1BF-53162BD027AA}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
README.md = README.md
|
||||||
|
TODO.md = TODO.md
|
||||||
|
.gitignore = .gitignore
|
||||||
|
.dockerignore = .dockerignore
|
||||||
|
.tool-versions = .tool-versions
|
||||||
|
.github\dependabot.yml = .github\dependabot.yml
|
||||||
|
.github\workflows\ci.yml = .github\workflows\ci.yml
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|||||||
@@ -8,5 +8,14 @@ Kard és Mágia karakter alkotó segédlet (https://app.kemkas.hu)
|
|||||||
|
|
||||||
## Coding readmes
|
## Coding readmes
|
||||||
|
|
||||||
|
To start development, spin up the docker-compose.yaml file and use the launchSettings.json to start the backend and frontend dev servers.
|
||||||
|
|
||||||
|
For the first time setup:
|
||||||
|
1. start the DB from the docker compose (required for the backend)
|
||||||
|
2. launch the project with the launchSettings file (will generate SSL certs)
|
||||||
|
3. spin up the proxy from docker compose (needs the SSL certs)
|
||||||
|
|
||||||
|
Later start the docker compose first and the project launch settings after the DB is up and running.
|
||||||
|
|
||||||
[Frontend README](./frontend/README.md)
|
[Frontend README](./frontend/README.md)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user