before restructering project

This commit is contained in:
Robert Nasarek 2022-09-08 15:50:11 +02:00
parent 99adc9c445
commit 9605a5b972
22 changed files with 733 additions and 210 deletions

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
# Build folder and files # # Build folder and files #
########################## ##########################
builds/ builds/
installers/
# Development folders and files # # Development folders and files #
################################# #################################

32
electron-builder.json Normal file
View file

@ -0,0 +1,32 @@
{
"appId": "org.nasarek.marvin",
"win": {
"target": "NSIS",
"icon": "marvin256x256.ico"
},
"nsis": {
"oneClick": false,
"installerIcon": "marvin256x256.ico",
"uninstallerIcon": "marvin256x256.ico",
"allowToChangeInstallationDirectory": true
},
"linux": {
"target": "deb",
"category": "Utility",
"icon": "marvin256x256.png"
},
"files": [
"*.js",
"**/*",
"./dist/bundle.css",
"./dist/index.html",
"./dist/main.js",
"./dist/main.js.LICENSE.txt",
"node_modules"
],
"extraResources": [{
"from": "resources/files",
"to": "files"
}
]
}

12
main.js
View file

@ -142,6 +142,16 @@ let mainMenu = Menu.buildFromTemplate(
] ]
) )
const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
: path.join(__dirname, '../../assets');
console.log(process.resourcesPath);
console.log(__dirname);
const getAssetPath = (paths) => {
return path.join(RESOURCES_PATH, paths);
};
function createWindow(dimensions) { function createWindow(dimensions) {
if (dev !== true) { if (dev !== true) {
@ -255,5 +265,3 @@ app.on('activate', () => {
} }
}) })
// IPC-Channel handling

BIN
marvin256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -33,25 +33,9 @@
"prod": "cross-env NODE_ENV=production webpack --mode production --config webpack.build.config.js && electron --noDevServer .", "prod": "cross-env NODE_ENV=production webpack --mode production --config webpack.build.config.js && electron --noDevServer .",
"start": "cross-env NODE_ENV=development webpack serve --hot --host 0.0.0.0 --config=./webpack.dev.config.js --mode development", "start": "cross-env NODE_ENV=development webpack serve --hot --host 0.0.0.0 --config=./webpack.dev.config.js --mode development",
"build": "cross-env NODE_ENV=production webpack --config webpack.build.config.js --mode production", "build": "cross-env NODE_ENV=production webpack --config webpack.build.config.js --mode production",
"installer": "electron-builder", "pack:installer": "electron-builder build -lw",
"package": "npm run build", "package": "npm run build",
"postpackage": "electron-packager ./ --ignore 'resources/files' --out=./builds --asar --overwrite --platform win32,linux --icon marvin.ico --extra-resource 'resources/files'" "postpackage": "electron-packager ./ --ignore \"(resources|builds|installer)\" --out=./builds --overwrite --platform win32,linux --icon marvin.ico --extra-resource 'resources/files'"
},
"build": {
"appId": "marvin",
"win": {
"target": [
"nsis"
],
"icon": "marvin256x256.ico"
},
"nsis": {
"oneClick": false,
"installerIcon": "marvin.ico",
"uninstallerIcon": "marvin.ico",
"uninstallDisplayName": "Marvin-Uninstaller",
"allowToChangeInstallationDirectory": true
}
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.10.0", "@emotion/react": "^11.10.0",
@ -60,10 +44,12 @@
"@mui/material": "^5.10.2", "@mui/material": "^5.10.2",
"about-window": "^1.15.2", "about-window": "^1.15.2",
"docx-templates": "^4.9.2", "docx-templates": "^4.9.2",
"image-resize-compress": "^1.0.8",
"postcss": "^8.4.16", "postcss": "^8.4.16",
"react": "^18.2.0", "react": "^18.2.0",
"react-async-devtools": "^10.0.1", "react-async-devtools": "^10.0.1",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-image-gallery": "^1.2.9",
"react-loader-spinner": "^5.3.3", "react-loader-spinner": "^5.3.3",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"replace-special-characters": "^1.2.6", "replace-special-characters": "^1.2.6",
@ -91,6 +77,7 @@
"postcss-nested": "^5.0.6", "postcss-nested": "^5.0.6",
"postcss-preset-env": "^7.8.0", "postcss-preset-env": "^7.8.0",
"postcss-pxtorem": "^6.0.0", "postcss-pxtorem": "^6.0.0",
"source-map-support": "^0.5.21",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"webpack": "^5.74.0", "webpack": "^5.74.0",
"webpack-cli": "^4.10.0", "webpack-cli": "^4.10.0",

View file

@ -1,3 +0,0 @@
{
"rootDir": "C:\\Users\\Robert\\Desktop\\marvin"
}

478
src/DocCreator.js Normal file
View file

@ -0,0 +1,478 @@
// Modules
import createReport from 'docx-templates';
import fs, {writeFile} from 'fs';
import {mkdir} from 'node:fs/promises';
import path from 'path';
import replaceSpecialCharacters from "replace-special-characters";
import {parseString, Builder} from 'xml2js';
////////////////////
// Main //
////////////////////
class DocCreator {
constructor(log, objectData) {
// Assign Log.
this.log = log;
// Assign general object data.
this.objectData = objectData;
// Get DateTime.
this.today = new Date();
// Get config file and parse to json.
this.configFile = fs.readFileSync('/resources/files/config/config.json')
this.configJson = JSON.parse(this.configFile.toString())
// Choose the template for selected document type.
switch (objectData.dokumenttyp) {
case 'rp':
this.documentInfo = {
documentType: 'restaurierungsprotokolle', docTypeAbbr: 'rp', templateFile: 'rp-template.docx',
}
break;
case 'lbb':
this.documentInfo = {
documentType: 'leihgabenbegleitblaetter', docTypeAbbr: 'lbb', templateFile: 'lbb-template.docx',
}
break;
case 'a':
this.documentInfo = {
documentType: 'analysen', docTypeAbbr: 'a', templateFile: 'a-template.docx',
}
break;
}
// ObjectId normalisation.
const normCharacterObjectId = replaceSpecialCharacters(objectData.inventarnummer);
this.normObjectId = normCharacterObjectId.replace("__", "_");
// Title normalisation
const replaceEszettTitle = objectData.titel.replace("ß", "-ss-");
let replaceUmlauteTitle = replaceEszettTitle.replace(/[^Ä]+/ig, "Ae");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ä]+/ig, "ae");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^Ö]+/ig, "Oe");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ö]+/ig, "oe");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^Ü]+/ig, "Ue");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ü]+/ig, "ue");
const normCharacterTitle = replaceSpecialCharacters(replaceUmlauteTitle);
const normSingleSpaceTitle = normCharacterTitle.replace("__", "_");
const normSpacingTitle = normSingleSpaceTitle.replace(/[^A-Z0-9\-]+/ig, "_");
this.normTitle = normSpacingTitle.slice(0, 50);
const folderName = this.normObjectId + '__' + this.normTitle
this.objectPath = path.join(this.configJson.rootDir, folderName);
this.documentPath = path.join(this.objectPath, this.documentInfo.documentType, objectData.datum);
this.filename = this.normObjectId + '__' + this.normTitle + '__' + this.objectData.datum + '__' + this.objectData.dokumenttyp;
this.filenameWithExtension = this.filename + '.docx'
this.temporaryWorkDirPath = path.join(this.objectPath, 'werkstatt');
}
// Fills the docx template.
async fillTemplate() {
// Variables
let buffer;
let configJson
// Create docx document if there was a response.
if (this.objectData.httpStatus === 200) {
try {
// Read template.
const template = fs.readFileSync(path.join('/resources/files/templates/', this.documentInfo.templateFile));
// Create report.
buffer = await createReport({
template, data: {
inventarnummer: this.objectData.inventarnummer ? this.objectData.inventarnummer : 'unbekannt',
titel: this.objectData.titel ? this.objectData.titel : 'unbekannt',
hersteller: this.objectData.hersteller ? this.objectData.hersteller : 'unbekannt',
herstellungsort: this.objectData.herstellungsort ? this.objectData.herstellungsort : 'unbekannt',
herstellungsdatum: this.objectData.herstellungsdatum ? this.objectData.herstellungsdatum : 'unbekannt',
materialTechnik: this.objectData.materialTechnik ? this.objectData.materialTechnik : 'unbekannt',
masse: this.objectData.masse ? this.objectData.masse : 'unbekannt'
}
});
} catch (err) {
// Set error log.
this.log = {
...this.log,
status: 'red',
message: 'Konnte Template nicht erstellen: ' + err,
tip: 'Ist das Template vorhanden?',
};
return this.log
}
try {
const createDocumentPath = await mkdir(this.documentPath, {recursive: true});
const createTemporaryWorkDirPath = await mkdir(this.temporaryWorkDirPath, {recursive: true});
} catch (err) {
// Set error log.
this.log = {
...this.log,
status: 'red',
message: 'Konnte den Pfad nicht erstellen' + err,
tip: 'Bestehen Schreibrechte auf dem Ordner?'
}
return this.log
}
// Write document to disk.
if (buffer) {
fs.writeFileSync(path.join(this.documentPath, this.filenameWithExtension), buffer)
this.log = {
...this.log, status: 'green', message: 'Dokument erstellt',
};
}
} else {
this.log = {
status: 'red',
message: 'Fehler bei der Kommunikation mit dem Objektkatalog',
code: this.objectData.httpStatus,
tip: 'Ist die Inventarnummer richtig?',
};
}
return this.log;
}
async createMetsMods() {
const metsModsString = `
<mets:mets
xmlns:mets="http://www.loc.gov/METS/"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="info:lc/xmlns/premis-v2
http://www.loc.gov/standards/premis/v2/premis-v2-0.xsd
http://www.loc.gov/mods/v3
http://www.loc.gov/standards/mods/v3/mods-3-6.xsd
http://www.loc.gov/METS/
http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd
http://www.loc.gov/mix/v10
http://www.loc.gov/standards/mix/mix10/mix10.xsd">
<mets:metsHdr createDate="${this.today}">
<mets:agent
type="other"
otherType="software"
role="creator">
<mets:name>
${process.env.REACT_APP_NAME} v${process.env.REACT_APP_VERSION}
</mets:name>
</mets:agent>
</mets:metsHdr>
<mets:fileSec>
<mets:fileGrp use="${this.documentInfo.documentType}">
<mets:file id="file__${this.filename}" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document">
<mets:FLocat locType="other" otherLocType="file" xlink:href="${this.filenameWithExtension}"/>
</mets:file>
</mets:fileGrp>
</mets:fileSec>
<mets:structMap type="physical">
<mets:div type="${this.documentInfo.docTypeAbbr}" id="phys_00" dmdid="dmdphys_00">
<mets:fptr fileId="file__${this.filename}"/>
</mets:div>
</mets:structMap>
<mets:structMap type="logical">
<mets:div type="${this.documentInfo.docTypeAbbr}" id="phys_00">
<mets:fptr fileId="file__${this.filename}"/>
</mets:div>
</mets:structMap>
<mets:dmdSec id="dmdlog_00">
<mets:mdWrap mdType="mods">
<mets:xmlData>
<mods:mods xmlns:mods="http://www.loc.gov/mods/v3">
<mods:recordInfo>
<mods:recordIdentifier source="https://objektkatalag.gnm.de">${this.objectData.inventarnummer}</mods:recordIdentifier>
</mods:recordInfo>
<mods:titleInfo>
<mods:title>${this.objectData.titel}</mods:title>
</mods:titleInfo>
<mods:originInfo>
<mods_dateIssued encoding="w3cdtf" keyDate="yes">${this.objectData.herstellungsdatum}</mods_dateIssued>
<mods:place>
<mods:placeTerm type="text">${this.objectData.herstellungsort}</mods:placeTerm>
</mods:place>
</mods:originInfo>
<mods:name type="personal">
<mods:role>
<mods:roleTerm authority="marcrelator" type="code">cre</mods:roleTerm>
</mods:role>
<mods:namePart>${this.objectData.herstellungsort}</mods:namePart>
<mods:displayForm>${this.objectData.herstellungsort}</mods:displayForm>
</mods:name>
<mods:physicalDescription>
<mods:form type="Material and Technique" lang="de"/>
<mods:extent>${this.objectData.masse}</mods:extent>
</mods:physicalDescription>
</mods:mods>
</mets:xmlData>
</mets:mdWrap>
</mets:dmdSec>
</mets:mets>
`
const metModsJson = {
'mets:mets': {
$: {
'xmlns:mets': "http://www.loc.gov/METS/",
'xmlns:xlink': "http://www.w3.org/1999/xlink",
'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
'xsi:schemaLocation': "info:lc/xmlns/premis-v2 http://www.loc.gov/standards/premis/v2/premis-v2-0.xsd " +
"http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-6.xsd " +
"http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd " +
"http://www.loc.gov/mix/v10 http://www.loc.gov/standards/mix/mix10/mix10.xsd"
},
'mets:metsHdr': {
$: {
// Creation date of the mets/mods xml.
'createDate': this.today // Should be w3ctdf format: YYYY-MM-DDThh:mm:ssTZD
},
'mets:agent': {
// App, which created the xml document
$: {
'type': 'other',
'otherType': 'software',
'role': 'creator'
},
'mets:name': {
// App name and version
_: `${process.env.REACT_APP_NAME} v${process.env.REACT_APP_VERSION}`
}
}
},
'mets:fileSec': {
'mets:fielGrp': {
$: {
// Documenttype
'use': `${this.documentInfo.documentType}`
},
'mets:file': {
// Phyical file
$: {
'id': `file__${this.filename}`,
'mimeType': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
},
'mets:FLocat': {
// Physical location - here in same folder
$: {
'locType': 'other',
'otherLocType': 'file',
'xlink:href': `${this.filenameWithExtension}`
}
}
}
}
},
'mets:structMap': [
{ // These are solo documents only, this may be inappropriate.
$: {
// Physical structure.
'type': 'physical'
},
'mets:div': {
$: {
// Documenttype and id.
'type': `${this.documentInfo.docTypeAbbr}`,
// since we have only one document, id and dmdid are static.
'id': `phys_00`,
'dmdid': 'dmdphys_00'
},
'mets:fptr': {
$: {
// File id from above
'fileId': `file__${this.filename}`
}
}
}
},
{ // These are solo documents only, this may be inappropriate.
$: {
// Physical structure.
'type': 'logical'
},
'mets:div': {
$: {
// Documenttype and id.
'type': `${this.documentInfo.docTypeAbbr}`,
// since we have only one document, id and dmdid are static.
'id': `phys_00`,
'dmdid': 'dmdphys_00'
},
'mets:fptr': {
$: {
// File id from above
'fileId': `file__${this.filename}`
}
}
}
}],
'mets:dmdSec':
{
$: {
// Since we have only one document, dmdlog is static
'id':
`dmdlog_00`
}
,
'mets:mdWrap':
{
$: {
'mdType':
'mods'
}
,
'mets:xmlData':
{
'mods:mods':
{
// Object properties as found at https://objektkatalog.gnm.de.
$: {
'xmlns:mods':
'http://www.loc.gov/mods/v3'
}
,
'mods:recordInfo':
{
'mods:recordIdentifier':
{
// ObjectId.
$: {
'source':
'https://objektkatalag.gnm.de'
}
,
_: `${this.objectData.inventarnummer}`
}
}
,
'mods:titleInfo':
{
// Title.
'mods:title':
{
_: `${this.objectData.titel}`
}
}
,
'mods:originInfo':
{
// Creation date.
'mods_dateIssued':
{
$: {
'encoding':
'w3cdtf', // W3C Date and Time, should be YYYY-MM-DDThh:mm:ssTZD
'keyDate':
'yes'
}
,
_: `${this.objectData.herstellungsdatum}`
}
,
'mods:place':
{
// Creation place
'mods:placeTerm':
{
$: {
'type':
'text'
}
,
_: `${this.objectData.herstellungsort}`
}
}
}
,
'mods:name':
{
// Creator.
$: {
'type':
'personal'
}
,
'mods:role':
{
'mods:roleTerm':
{
$: {
'authority':
'marcrelator',
'type':
'code'
}
,
_: 'cre'
}
}
,
'mods:namePart':
{
_: this.objectData.hersteller
}
,
'mods:displayForm':
{
_: this.objectData.hersteller
}
}
,
'mods:physicalDescription':
{
'mods:form':
{
$: {
'type':
'Material and Technique',
'lang':
'de'
}
}
,
'mods:extent':
{
_: `${this.objectData.masse}`
}
}
}
}
}
}
}
}
let metModsXml
parseString(metsModsString, {trim: true},
function (err, result) {
metModsXml = result;
}
);
console.log(metModsXml, 'from string');
const builder = new Builder()
metModsXml = builder.buildObject(metModsJson);
console.log(metModsXml, 'from Json')
const fileName = `.metsMods__${this.normObjectId}__${this.normTitle}.xml`
fs.writeFileSync(path.join(this.documentPath,fileName),metModsXml.toString(),
function (err) {
if (err) {
console.log(err);
} else {
console.log("The file was saved!");
}
}
)
return true;
}
}
export {DocCreator};

View file

@ -1,116 +0,0 @@
// Modules
import createReport from 'docx-templates';
import fs from 'fs';
import { mkdir } from 'node:fs/promises';
import path from 'path';
import replaceSpecialCharacters from "replace-special-characters";
////////////////////
// Main //
////////////////////
// Fills the docx template.
export async function fillTemplate(log, objectData) {
// Variables
let buffer;
let configJson
// Create docx document if there was a response.
if (objectData.httpStatus === 200) {
let documentInfo;
try {
// Load config file.
let ConfigFile = fs.readFileSync('resources/files/config/config.json')
configJson = JSON.parse(ConfigFile)
// Choose the template for selected document type.
switch (objectData.dokumenttyp) {
case 'rp':
documentInfo = {
documentType: 'restaurierungsprotokolle',
templateFile: 'rp-template.docx',
}
break;
case 'lbb':
documentInfo = {
documentType: 'leihgabenbegleitblaetter',
templateFile: 'lbb-template.docx',
}
break;
case 'a':
documentInfo = {
documentType: 'analysen',
templateFile: 'a-template.docx',
}
break;
}
// Read template.
const template = fs.readFileSync(path.join('resources/files/templates/', documentInfo.templateFile));
// Create report.
buffer = await createReport({
template,
data: {
inventarnummer: objectData.inventarnummer ? objectData.inventarnummer : 'unbekannt' ,
titel: objectData.titel ? objectData.titel : 'unbekannt',
hersteller: objectData.hersteller ? objectData.hersteller : 'unbekannt',
herstellungsort: objectData.herstellungsort ? objectData.herstellungsort : 'unbekannt',
herstellungsdatum: objectData.herstellungsdatum ? objectData.herstellungsdatum : 'unbekannt',
materialTechnik: objectData.materialTechnik ? objectData.materialTechnik : 'unbekannt' ,
masse: objectData.masse ? objectData.masse : 'unbekannt'
}
});
} catch (err) {
// Set error log.
log = {
...log,
status: 'red',
message: 'Konnte Template nicht erstellen: ' + err,
tip: 'Ist das Template vorhanden?',
};
return log
}
// Create folder (if necessary).
const objectPath = path.join(configJson.rootDir, objectData.inventarnummer);
const documentPath = path.join(objectPath, documentInfo.documentType);
const temporaryWorkDirPath = path.join(objectPath, 'werkstatt');
try {
const createDocumentPath = await mkdir(documentPath, {recursive: true});
const createTemporaryWorkDirPath = await mkdir(temporaryWorkDirPath, {recursive: true});
} catch (err) {
// Set error log.
log = {
...log,
status: 'red',
message: 'Konnte den Pfad nicht erstellen' + err,
tip: 'Bestehen Schreibrechte auf dem Ordner?'
}
return log
}
// Write document to disk.
if (buffer) {
const normCharacterObjectId = replaceSpecialCharacters(objectData.inventarnummer)
const normCharacterTitle = replaceSpecialCharacters(objectData.titel)
const normSpacingTitle = normCharacterTitle.replace(/[^A-Z0-9]+/ig, "_");
const filename = objectData.datum + '_' + normCharacterObjectId + '_' + normSpacingTitle + '.docx'
fs.writeFileSync(path.join(documentPath, filename), buffer)
log = {
...log,
status: 'green',
message: 'Dokument erstellt',
};
}
} else {
log = {
status: 'red',
message: 'Fehler bei der Kommunikation mit dem Objektkatalog',
code: objectData.httpStatus,
tip: 'Ist die Inventarnummer richtig?',
};
}
return log;
}

30
src/Image.js Normal file
View file

@ -0,0 +1,30 @@
import {blobToURL, fromURL} from "image-resize-compress";
class Image {
constructor(originalUri, originalHeight = '300px', originalWidth = '200px', loading = 'lazy') {
this.original = originalUri;
this.originalHeight = originalHeight;
this.originalWidth = originalWidth;
this.loading = loading;
(async () => {
this.thumbnail = await this.convert2Thumbnail(this.original)
})();
}
convert2Thumbnail = async (sourceUrl) => {
// quality value for webp and jpeg formats.
const quality = 80;
// output width. 0 will keep its original width and 'auto' will calculate its scale from height.
const width = 100;
// output height. 0 will keep its original height and 'auto' will calculate its scale from width.
const height = 'auto';
// file format: png, jpeg, bmp, gif, webp. If null, original format will be used.
const format = 'webp';
// note only the sourceUrl argument is required
let blob = await fromURL(sourceUrl, quality, width, height, format);
return await blobToURL(blob);
};
}
export {Image};

View file

@ -18,12 +18,14 @@ class ObjektkatalogApi {
masse: '', masse: '',
materialTechnik: '', materialTechnik: '',
titel: '', titel: '',
wisskiUri: '',
}; };
response; response;
visibility; visibility;
// Get data from objektkatalog.gnm.de. // Get data from objektkatalog.gnm.de.
async getData(objectId) { async getData(objectId) {
if (objectId) { if (objectId) {
// RESTful GET. // RESTful GET.
@ -50,6 +52,7 @@ class ObjektkatalogApi {
eid: responseJson[0]['eid'], eid: responseJson[0]['eid'],
allgemeineBezeichnung: responseJson[0]['fc6392714594e73ddb2fa363815a8fdf'], allgemeineBezeichnung: responseJson[0]['fc6392714594e73ddb2fa363815a8fdf'],
beschreibung: responseJson[0]['f81f557caccf45074edfb65ff077011f'], beschreibung: responseJson[0]['f81f557caccf45074edfb65ff077011f'],
bilder: responseJson[0]['f41dae62df47283958f605716d141ebf'],
darstellung: responseJson[0]['f217e1053b1e29411d4b00f3b1e1d52b'], darstellung: responseJson[0]['f217e1053b1e29411d4b00f3b1e1d52b'],
erwerbsmethode: responseJson[0]['fa4aa035d411275cd36a2fbb5c159a2c'], erwerbsmethode: responseJson[0]['fa4aa035d411275cd36a2fbb5c159a2c'],
fruehstes: responseJson[0]['ff4a178095c895a12fce6320c04ba0b0'], fruehstes: responseJson[0]['ff4a178095c895a12fce6320c04ba0b0'],
@ -71,6 +74,7 @@ class ObjektkatalogApi {
titel: responseJson[0]['f2049b2456b20f8fd80f714e154f1d47'], titel: responseJson[0]['f2049b2456b20f8fd80f714e154f1d47'],
unterbringung: responseJson[0]['f15265e39237868a568ee63453492b17'], unterbringung: responseJson[0]['f15265e39237868a568ee63453492b17'],
vitrinentext: responseJson[0]['fe5e3ff18aedf1d25c639dc79fb24ad1'], vitrinentext: responseJson[0]['fe5e3ff18aedf1d25c639dc79fb24ad1'],
wisskiUri: responseJson[0]['wisski_uri'][0]['value'],
zustandsbeschreibung: responseJson[0]['f54b6da6006ea444c33a348b8c4370a8'] zustandsbeschreibung: responseJson[0]['f54b6da6006ea444c33a348b8c4370a8']
} }
break; break;
@ -118,6 +122,16 @@ class ObjektkatalogApi {
return [this.receivedData, this.visibility] return [this.receivedData, this.visibility]
} }
// Bilder
let bilder =[];
if (this.raw.bilder.length !== 0) {
for (const bildIndex in this.raw.bilder) {
bilder.push(this.raw.bilder[bildIndex].url)
}
} else {
this.bilder = null;
}
// Datum // Datum
// Default date of today // Default date of today
let today = new Date() let today = new Date()
@ -187,9 +201,11 @@ class ObjektkatalogApi {
}) })
} }
// Json with important data. // Json with important data.
this.receivedData = { this.receivedData = {
...this.receivedData, ...this.receivedData,
bilder: bilder,
datum: todayFormat, datum: todayFormat,
titel: titel, titel: titel,
hersteller: hersteller, hersteller: hersteller,
@ -198,6 +214,7 @@ class ObjektkatalogApi {
inventarnummer: inventarnummer, inventarnummer: inventarnummer,
materialTechnik: materialTechnik, materialTechnik: materialTechnik,
masse: masse, masse: masse,
wisskiUri: this.raw.wisskiUri,
httpStatus: 200, httpStatus: 200,
} }
this.visibility = true this.visibility = true

View file

@ -0,0 +1,3 @@
{
"rootDir": "/home/rbrt/Schreibtisch/boehler"
}

View file

@ -1,4 +1,7 @@
/* Imports */
@import url('https://fonts.googleapis.com/css?family=Open+Sans'); @import url('https://fonts.googleapis.com/css?family=Open+Sans');
@import "react-image-gallery/styles/css/image-gallery.css";
a { a {
color: #d5d5d5; color: #d5d5d5;
@ -23,6 +26,10 @@ body {
.checkup { .checkup {
transition: height 1s; transition: height 1s;
height: 0; height: 0;
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
} }
.closed{ .closed{
@ -43,10 +50,6 @@ body {
max-width: max-content; max-width: max-content;
} }
div {
padding: 0.5em;
}
.edit-button { .edit-button {
background-color: #e30f27; background-color: #e30f27;
color: #d5d5d5; color: #d5d5d5;
@ -55,6 +58,7 @@ div {
border: unset; border: unset;
padding: 0 4px; padding: 0 4px;
height: 1.5rem; height: 1.5rem;
border-radius: 0 .1875rem .1875rem 0;
} }
.edit-input { .edit-input {
@ -87,6 +91,23 @@ div {
background-color: darkgreen; background-color: darkgreen;
} }
h3 {
color: #464646;
}
.image-gallery {
flex: .5 .5 50%;
}
.image-gallery-thumbnails-container {
display: flex;
justify-content: center;
}
.image-gallery-slide-wrapper {
margin-bottom: .5rem;
}
.inactive { .inactive {
display: none; display: none;
} }
@ -129,6 +150,10 @@ input.edit-input:not(:disabled) {
font-family: "Open Sans", sans-serif; font-family: "Open Sans", sans-serif;
} }
.justify-content-center {
display: flex;
justify-content: center;
}
.justify-content-end { .justify-content-end {
@ -168,13 +193,16 @@ label {
} }
.open { .open {
height: 610px; height: 100%;
overflow: hidden; overflow: hidden;
} }
p { p {
margin: 0; margin: 0;
} }
.pd-05rem {
padding: .5rem;
}
.position-absolute { .position-absolute {
position: absolute; position: absolute;
} }
@ -223,15 +251,15 @@ select {
} }
.settings-div { .settings-div {
background-color: #d5d5d5; background-color: #f2f2f2;
color: black; color: black;
width: 300px; width: 388px;
border-top: none; border-top: none;
border-right: none; border-right: none;
border-left: none; border-left: none;
border-bottom: 0.125rem solid #e30019; border-bottom: 0.125rem solid #e30019;
border-radius: 0.1875rem; border-radius: .1875rem 0 0 .1875rem;
overflow-x: scroll; overflow-x: auto;
white-space:nowrap; white-space:nowrap;
} }
@ -256,10 +284,13 @@ textarea.select-folder-field, textarea.select-folder-field:focus, input.select-f
} }
.v-distance { .v-distance {
margin-top: 0.25em; margin-top: 0.25rem;
margin-bottom: 0.25em; margin-bottom: 0.25rem;
} }
.bottom-distance {
margin-bottom: 1rem;
}
/* width */ /* width */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 5px; width: 5px;

View file

Before

Width:  |  Height:  |  Size: 434 B

After

Width:  |  Height:  |  Size: 434 B

Before After
Before After

View file

@ -1,6 +1,13 @@
// Components // Components
import {DataForm} from "./DataForm"; import {DataForm} from "./DataForm";
import {Log} from "./Log" import {Log} from "./Log"
// CSS
import '../assets/css/styles.css'
import {LoadingIcon} from "./LoadingIcon";
// Icons
import SettingsIcon from '@mui/icons-material/Settings'; import SettingsIcon from '@mui/icons-material/Settings';
// Modules // Modules
@ -10,10 +17,6 @@ import ObjektkatalogApi from "../ObjektkatalogApi";
import {NavLink} from "react-router-dom"; import {NavLink} from "react-router-dom";
import React, {useState} from 'react' import React, {useState} from 'react'
// CSS
import '../assets/css/styles.css'
import {LoadingIcon} from "./LoadingIcon";
//////////////////// ////////////////////
// Main // // Main //
@ -91,8 +94,21 @@ export const App = () => {
await setLogState({ await setLogState({
log: { log: {
status: 'red', status: 'red',
message: 'Objektkatalog nicht erreichbar!', message: 'Objektkatalog kann sich nicht um die Anfrage kümmern!',
code: '503', code: '503',
tip: 'Vielleicht hat der Katalog gerade sehr viele Zugriffe, probieren Sie es später noch einmal.',
}, // with message, code, tip
logClass: 'active'
})
// Hide Loading
setIsLoading(false)
return;
case 404:
await setLogState({
log: {
status: 'red',
message: 'Objektkatalog nicht erreichbar!',
code: '404',
tip: 'Sind sie mit dem Internet verbunden und ist der Objektkatalog online?', tip: 'Sind sie mit dem Internet verbunden und ist der Objektkatalog online?',
}, // with message, code, tip }, // with message, code, tip
logClass: 'active' logClass: 'active'
@ -170,7 +186,9 @@ export const App = () => {
<NavLink className={'nav-icon'} to="/settings"><SettingsIcon/></NavLink> <NavLink className={'nav-icon'} to="/settings"><SettingsIcon/></NavLink>
</nav> </nav>
</header> </header>
<main> <main className={"bottom-distance"}>
<h3 className={"flex-center"}>Marvin</h3>
<section>
<div className={"container"}> <div className={"container"}>
<form id={"object-id-form"} className={"flex-wrap"}> <form id={"object-id-form"} className={"flex-wrap"}>
<div className={"center column flex justify-content-space-between "}> <div className={"center column flex justify-content-space-between "}>
@ -198,6 +216,8 @@ export const App = () => {
</form> </form>
</div> </div>
<LoadingIcon isLoading={isLoading}/> <LoadingIcon isLoading={isLoading}/>
</section>
<section>
<DataForm <DataForm
checkUpVisibility={checkUpVisibility} checkUpVisibility={checkUpVisibility}
objectData={objectData} objectData={objectData}
@ -205,6 +225,7 @@ export const App = () => {
logState={logState} logState={logState}
setLogState={setLogState} setLogState={setLogState}
/> />
</section>
</main> </main>
<footer> <footer>
{/* We give state and state setter of the parent as params to the child components, so that child events can change parent states */} {/* We give state and state setter of the parent as params to the child components, so that child events can change parent states */}

View file

@ -1,5 +1,8 @@
// Components
import {Galary} from './Galary'
// Modules // Modules
import {fillTemplate} from "../DocxInserter"; import {DocCreator} from "../DocCreator";
// React // React
import React from 'react' import React from 'react'
@ -98,7 +101,10 @@ export const DataForm = ({checkUpVisibility, objectData, setObjectData, logState
// Fill the template and save it. // Fill the template and save it.
const fillTemplateClickHandler = async (e) => { const fillTemplateClickHandler = async (e) => {
e.preventDefault(); e.preventDefault();
log = await fillTemplate(logState, objectData); const docCreator = new DocCreator(logState, objectData)
log = await docCreator.fillTemplate();
const metsMods = await docCreator.createMetsMods();
// Set new state of log div with message and visibility class // Set new state of log div with message and visibility class
setLogState({ setLogState({
log: log, log: log,
@ -107,8 +113,11 @@ export const DataForm = ({checkUpVisibility, objectData, setObjectData, logState
} }
// Renders data form // Renders data form
return (<div className={'checkup ' + (checkUpVisibility ? 'open' : 'closed')}> return (
<form className={'flex column '}> <div className={'checkup ' + (checkUpVisibility ? 'open' : 'closed')}>
<form className={'flex column pd-05rem'}>
<Galary objectData={objectData}/>
<div>
<div > <div >
<label htmlFor={'template-datum'} >Datum</label> <label htmlFor={'template-datum'} >Datum</label>
<input <input
@ -198,6 +207,7 @@ export const DataForm = ({checkUpVisibility, objectData, setObjectData, logState
onChange={masseChangeHandler} onChange={masseChangeHandler}
/> />
</div> </div>
</div>
<button <button
type={"submit"} type={"submit"}
className={'send-button center top-distance'} className={'send-button center top-distance'}

22
src/components/Galary.js Normal file
View file

@ -0,0 +1,22 @@
import React from 'react';
import {Image} from "../Image";
import ImageGallery from 'react-image-gallery';
////////////////////
// Main //
////////////////////
export const Galary = ({objectData}) => {
let images =[];
if (objectData.bilder) {
for (const imageIndex in objectData.bilder) {
images.push(new Image(objectData.bilder[imageIndex]));
}
}
return (
<ImageGallery items={images} showFullscreenButton={false} showPlayButton={false} showThumbnails={false} disableKeyDown={true}/>
);
}
export default Galary;

View file

@ -15,7 +15,7 @@ export const Log = ({logState, setLogState}) => {
logClass: 'inactive'}); logClass: 'inactive'});
} }
const classes = 'round-box flex ' + logState.log.status + ' ' + logState.logClass const classes = 'round-box flex pd-05rem ' + logState.log.status + ' ' + logState.logClass
if (logState.log.code) { if (logState.log.code) {
code = ' Code: ' + logState.log.code code = ' Code: ' + logState.log.code
} else { } else {
@ -29,10 +29,10 @@ export const Log = ({logState, setLogState}) => {
return ( return (
<div className={'log '}> <div className={'log '}>
<div id={'log-content'} className={classes}> <div id={'log-content'} className={classes}>
<div> <div className={"log-close-button"}>
<button onClick={closeLog}>x</button> <button onClick={closeLog}>x</button>
</div> </div>
<div className={'scroll-y flex-full'} style={{maxHeight: 4 + 'em'}}> <div className={'scroll-y flex-full pd-05rem'} style={{maxHeight: 4 + 'em'}}>
<p>{logState.log.message}</p> <p>{logState.log.message}</p>
<p>{code}</p> <p>{code}</p>
<p>{tip}</p> <p>{tip}</p>

View file

@ -1,8 +1,8 @@
// Config // Modules
import configImport from '/resources/files/config/config.json' import path from "path";
// Components // Config
import {Log} from "../components/Log"; import configImport from '/src/assets/config/config.json'
// Icons // Icons
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
@ -48,8 +48,9 @@ export default function Settings() {
rootDir: rootDirFromWindow rootDir: rootDirFromWindow
} }
if (rootDirFromWindow) { if (rootDirFromWindow) {
console.log(__dirname);
let message; let message;
await writeFile('resources/files/config/config.json', JSON.stringify(config2Safe, null, 2), (err) => { await writeFile('/resources/files/config/config.json', JSON.stringify(config2Safe, null, 2), (err) => {
if (err) { if (err) {
message = err; message = err;
} else { } else {
@ -68,11 +69,13 @@ export default function Settings() {
<NavLink className={'nav-icon'} to="/"><ArrowBackIosIcon/></NavLink> <NavLink className={'nav-icon'} to="/"><ArrowBackIosIcon/></NavLink>
</header> </header>
<main> <main>
<form onSubmit={selectFolderHandler}> <section className={"flex-center column"}>
<label htmlFor={"output-root"}> <h3>Einstellungen</h3>
<form onSubmit={selectFolderHandler} className={"pd-05rem"}>
<label className={"center cut v-distance"} htmlFor={"output-root"}>
Hauptverzeichnis Hauptverzeichnis
</label> </label>
<div className="col-sm-10 d-flex align-items-center flex sticky-edit"> <div className="align-items-center flex">
<Input config={config} setConfig={setConfig}/> <Input config={config} setConfig={setConfig}/>
<button type="submit" className="edit-button text-end"> <button type="submit" className="edit-button text-end">
<i className="fas fa-edit d-block"> <i className="fas fa-edit d-block">
@ -81,6 +84,7 @@ export default function Settings() {
</button> </button>
</div> </div>
</form> </form>
</section>
</main> </main>
<footer> <footer>
</footer> </footer>

View file

@ -12,25 +12,23 @@ module.exports = {
{ {
test: /\.css$/, test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'postcss-loader' }], use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'postcss-loader' }],
include: defaultInclude
}, },
{ {
test: /\.jsx?$/, test: /\.jsx?$/,
use: [{ loader: 'babel-loader' }], use: [{ loader: 'babel-loader' }],
include: defaultInclude
}, },
{ {
test: /\.(jpe?g|png|gif)$/, test: /\.(jpe?g|png|gif)$/,
use: [{ loader: 'file-loader?name=img/[name]__[hash:base64:5].[ext]' }], use: [{ loader: 'file-loader?name=img/[name]__[hash:base64:5].[ext]' }],
include: defaultInclude
}, },
{ {
test: /\.(eot|svg|ttf|woff|woff2)$/, test: /\.(eot|svg|ttf|woff|woff2)$/,
use: [{ loader: 'file-loader?name=font/[name]__[hash:base64:5].[ext]' }], use: [{ loader: 'file-loader?name=font/[name]__[hash:base64:5].[ext]' }],
include: defaultInclude
} }
] ]
}, },
target: 'electron-renderer', target: 'electron-renderer',
plugins: [ plugins: [
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({