Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mnes 1186 add sqlite db #69

Merged
merged 18 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ cypress-artifacts
.env
/cypress/videos/
/cypress/screenshots/
/prisma/mnestix-database.db
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ FROM deps AS builder
WORKDIR /app
COPY . .

RUN yarn prisma migrate deploy
RUN yarn prisma generate

RUN yarn build

FROM base AS production
Expand All @@ -39,4 +42,7 @@ FROM deps AS dev
ENV NODE_ENV=development
COPY . .

RUN yarn prisma migrate deploy
RUN yarn prisma generate

CMD [ "yarn", "dev"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ Mnestix provides the following configuration options. You can adapt the values i
| `THEME_LOGO_URL` | | This variable **overwrites** the Logo in the theme, and thus the environment variable `THEME_LOGO_MIME_TYPE` will not be evaluated and it is not necessary to mount the image as specified below | optional |
| `KEYCLOAK_ENABLED` | false | By default, it is set to false, meaning Keycloak authentication will be disabled, and the default authentication method will be Azure Entra ID. If you set this variable to true, Keycloak authentication will be enabled instead. | optional |
| `KEYCLOAK_CLIENT_ID` | mnestix-browser-client-demo | Configuration variable that specifies the client unique identifier used by your application when connecting to the Keycloak server. | optional |
| `KEYCLOAK_ISSUER` | | Configuration variable that specifies the URL of the Keycloak servers issuer endpoint. This endpoint provides the base URL for the Keycloak server that issues tokens and handles authentication requests | optional |
| `KEYCLOAK_ISSUER` | | Configuration variable that specifies the URL of the Keycloak servers issuer endpoint. This endpoint provides the base URL for the Keycloak server that issues tokens and handles authentication requests | optional |
| `KEYCLOAK_LOCAL_URL` | | Optional configuration variable specifically used for development environments within Docker. This allows your application to connect to a Keycloak instance running in a Docker container | optional |
| `KEYCLOAK_REALM` | BaSyx | Configuration variable that specifies the name of the Keycloak realm your application will use for authentication and authorization. | optional |

Expand Down
5 changes: 5 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ networks:
mnestix-network:
driver: bridge
name: mnestix-network

volumes:
mnestix-database:

services:
mnestix-browser:
Expand Down Expand Up @@ -29,6 +32,8 @@ services:
condition: service_healthy # only after the healthcheck in aas is successful, the mnestix container is being created
networks:
- mnestix-network
volumes:
- mnestix-database:/app/prisma/database

mnestix-api:
image: mnestix/mnestix-api:latest
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"@types/flat": "^5.0.5",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.0",
"@types/node": "^20.12.7",
"@types/node": "^22.4.2",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
"@typescript-eslint/eslint-plugin": "^7.7.1",
Expand All @@ -26,6 +26,7 @@
"globals": "^15.1.0",
"lodash": "^4.17.21",
"prettier": "^3.2.5",
"prisma": "^5.18.0",
"typescript-eslint": "^7.8.0"
},
"dependencies": {
Expand All @@ -46,6 +47,7 @@
"@mui/styled-engine": "latest",
"@mui/x-date-pickers": "^7.2.0",
"@mui/x-tree-view": "^7.3.0",
"@prisma/client": "^5.18.0",
"@svgr/webpack": "^8.1.0",
"buffer": "^6.0.3",
"date-fns": "^2.28.0",
Expand All @@ -63,6 +65,7 @@
"react-intl": "^6.6.5",
"recharts": "^2.12.6",
"sass": "^1.75.0",
"sqlite3": "^5.1.7",
"typescript": "^5.4.5",
"url": "^0.11.3",
"web-vitals": "^3.5.2"
Expand All @@ -71,9 +74,9 @@
"string-width": "4.2.3"
},
"scripts": {
"dev": "next dev",
"dev": "yarn prisma migrate deploy && yarn prisma generate && next dev",
"build": "next build",
"start": "next start",
"start": "yarn prisma migrate deploy && yarn prisma generate && next start",
"prettier": "prettier --check ./",
"format": "prettier --write ./",
"lint": "next lint",
Expand Down
24 changes: 24 additions & 0 deletions prisma/migrations/20240822112149_0_init_db/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-- CreateTable
CREATE TABLE "ConnectionType" (
"id" TEXT NOT NULL PRIMARY KEY,
"typeName" TEXT NOT NULL
);

-- CreateTable
CREATE TABLE "MnestixConnection" (
"id" TEXT NOT NULL PRIMARY KEY,
"url" TEXT NOT NULL,
"typeId" TEXT NOT NULL,
CONSTRAINT "MnestixConnection_typeId_fkey" FOREIGN KEY ("typeId") REFERENCES "ConnectionType" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);

--- CHANGED MANUALLY ---
-- Insert ConnectionType Enum values as SQLite does not support Enums
-- Create a new migration if you need to expand this Enum!
INSERT INTO "ConnectionType" (id, typeName)
VALUES (0, 'AAS_REPOSITORY'),
(1, 'AAS_REGISTRY'),
(2, 'SUBMODEL_REPOSITORY'),
(3, 'SUBMODEL_REGISTRY'),
(4, 'DISCOVERY_SERVICE'),
(5, 'CONCEPT_DESCRIPTION');
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "sqlite"
25 changes: 25 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This is our Prisma schema file.
// Changing the schema requires a new migration to apply those changes to all database instances.
// Migrations can be generated by prisma.

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "sqlite"
url = "file:./database/mnestix-database.db"
}

model ConnectionType {
id String @id @default(cuid())
typeName String
connection MnestixConnection[]
}

model MnestixConnection {
id String @id @default(cuid())
url String
type ConnectionType @relation(fields: [typeId], references: [id])
typeId String
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function IdSettingsCard(props: IdSettingsCardProps) {
}
}
return (
<Paper sx={{ p: 3, width: '100%' }}>
<Box sx={{ p: 3, width: '100%' }}>
<CardHeading
title={<FormattedMessage {...messages.mnestix.idStructure} />}
subtitle={<FormattedMessage {...messages.mnestix.idStructureExplanation} />}
Expand Down Expand Up @@ -86,6 +86,6 @@ export function IdSettingsCard(props: IdSettingsCardProps) {
open={documentationModalOpen}
onClose={() => setDocumentationModalOpen(false)}
/>
</Paper>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { CardHeading } from 'components/basics/CardHeading';
import { FormattedMessage } from 'react-intl';
import { messages } from 'lib/i18n/localization';
import { Box } from '@mui/material';

export function MnestixConnectionsCard() {
return (
<Box sx={{p: 3, width: '100%'}}>
<CardHeading
title={<FormattedMessage {...messages.mnestix.mnestixConnections} />}
subtitle={<FormattedMessage {...messages.mnestix.mnestixConnectionsExplanation} />}
/>
<Box minHeight='300px'>
todo: content will follow
</Box>
</Box>
);
}
62 changes: 50 additions & 12 deletions src/app/[locale]/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use client';

import { PrivateRoute } from 'components/azureAuthentication/PrivateRoute';
import { Box } from '@mui/material';
import { Box, Card } from '@mui/material';
import { FormattedMessage, useIntl } from 'react-intl';
import { ViewHeading } from 'components/basics/ViewHeading';
import { TabSelectorItem, VerticalTabSelector } from 'components/basics/VerticalTabSelector';
import { messages } from 'lib/i18n/localization';
import { useState } from 'react';
import { IdGenerationSettingFrontend } from 'lib/types/IdGenerationSettingFrontend';
Expand All @@ -20,16 +21,35 @@ import { useAsyncEffect } from 'lib/hooks/UseAsyncEffect';
import { useAuth } from 'lib/hooks/UseAuth';
import { IdSettingsCard } from './_components/id-settings/IdSettingsCard';
import { useApis } from 'components/azureAuthentication/ApiProvider';
import { useIsMobile } from 'lib/hooks/UseBreakpoints';
import { MnestixConnectionsCard } from 'app/[locale]/settings/_components/mnestix-connections/MnestixConnectionsCard';

enum settingsPageTypes {
ID_STRUCTURE,
MNESTIX_CONNECTIONS
}

export default function Page() {
const notificationSpawner = useNotificationSpawner();
const intl = useIntl();
const [settings, setSettings] = useState<IdGenerationSettingFrontend[]>([]);
const [isLoading, setIsLoading] = useState(false);
const isMobile = useIsMobile();

const settingsTabItems: TabSelectorItem[] = [
{
id: settingsPageTypes[settingsPageTypes.ID_STRUCTURE],
label: intl.formatMessage(messages.mnestix.idStructure)
},
{
id: settingsPageTypes[settingsPageTypes.MNESTIX_CONNECTIONS],
label: intl.formatMessage(messages.mnestix.mnestixConnections)
}]
const [selectedTab, setSelectedTab] = useState<TabSelectorItem>(settingsTabItems[0]);

const auth = useAuth();
const bearerToken = auth.getBearerToken();
const { configurationClient } = useApis();
const {configurationClient} = useApis();

const fetchSettings = async () => {
try {
Expand Down Expand Up @@ -105,19 +125,37 @@ export default function Page() {
await fetchSettings();
}, [bearerToken]);


const renderActiveSettingsTab = () => {
switch (selectedTab.id) {
case settingsPageTypes[settingsPageTypes.ID_STRUCTURE]:
return <IdSettingsCard
idSettings={settings}
isLoading={isLoading}
handleChange={handleChangeIdGeneratorSetting}
/>
case settingsPageTypes[settingsPageTypes.MNESTIX_CONNECTIONS]:
return <MnestixConnectionsCard/>
default:
return <></>
}
}

return (
<PrivateRoute>
<Box sx={{ p: 3, maxWidth: '1125px', width: '100%', margin: '0 auto' }}>
<Box sx={{ mb: 3 }}>
<ViewHeading title={<FormattedMessage {...messages.mnestix.settings} />} />
{/* TODO: Place action buttons here (e.g. specification button) */}
<Box sx={{p:4, width: '100%', margin: '0 auto'}}>
<Box sx={{mb: 3}}>
<ViewHeading title={<FormattedMessage {...messages.mnestix.settings} />}/>
</Box>
<Box sx={{ mb: 3 }}>
<IdSettingsCard
idSettings={settings}
isLoading={isLoading}
handleChange={handleChangeIdGeneratorSetting}
/>
<Card sx={{mb: 3}}>
<Box display="grid" gridTemplateColumns={isMobile ? '1fr' : '1fr 3fr'}>
<VerticalTabSelector items={settingsTabItems} selected={selectedTab}
setSelected={setSelectedTab}/>
{renderActiveSettingsTab()}
</Box>
</Card>
<Box>
<p>{}</p>
</Box>
</Box>
</PrivateRoute>
Expand Down
36 changes: 36 additions & 0 deletions src/app/api/mnestixConnections/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { prisma } from 'lib/database/prisma';
import { NextRequest } from 'next/server';

export async function GET() {
try {
const mnestixConnections = await prisma.mnestixConnection.findMany({include: {type: true}})

return Response.json(mnestixConnections);
} catch (error) {
return Response.json({ error: (error as Error).message });
}
}

export async function POST(req: NextRequest) {
const mnestixConnectionRequest = await req.json()

if (!mnestixConnectionRequest.url || !mnestixConnectionRequest.type) {
return Response.json({ error: 'Url and type are required' });
}

try {
const mnestixType = await prisma.connectionType.findFirst({ where: { typeName: mnestixConnectionRequest.type } })
if (!mnestixType) {
return Response.json({ error: 'Invalid type' })
}
await prisma.mnestixConnection.create({
data: {
url: mnestixConnectionRequest.url,
typeId: mnestixType.id
}
})
return Response.json({ message: 'MnestixConnection created' });
} catch (error) {
return Response.json({ error: (error as Error).message });
}
}
17 changes: 17 additions & 0 deletions src/lib/database/prisma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { PrismaClient } from '@prisma/client';

/**
* For using prisma with Next.js, it is recommended to use the PrismaClient as Singleton.
*/
const prismaClientSingleton = () => {
return new PrismaClient();
};

declare global {
// eslint-disable-next-line
var prisma: undefined | ReturnType<typeof prismaClientSingleton>;
}

export const prisma = globalThis.prisma ?? prismaClientSingleton();

if (process.env.NODE_ENV !== 'production') globalThis.prisma = prisma;
2 changes: 2 additions & 0 deletions src/lib/i18n/de.mnestix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export const deMnestix = {
idStructure: 'ID Struktur',
idStructureExplanation:
'Definieren Sie, wie Ihre IDs aussehen sollen. Dies ist eine Basis-Einstellung, die für individuelle Importe angepasst werden kann.',
mnestixConnections: 'Mnestix Quellen',
mnestixConnectionsExplanation: 'Definieren Sie, welche Daten Quellen verwendet werden sollen.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR, but do we really want to use the formal "Sie" instead of just "Definiere, welche [...]"?

submodels: 'Submodelle',
unknownModelType: 'Unbekannter ModelType: {type}',
nameplateAddressTypes: {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/i18n/en.mnestix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export const enMnestix = {
idStructure: 'ID structure',
idStructureExplanation:
'Define, how your IDs are represented. This is a standard setting that can be adjusted for individual imports.',
mnestixConnections: 'Mnestix Connections',
mnestixConnectionsExplanation: 'Define which data connections should be used.',
submodels: 'Submodels',
unknownModelType: 'Unknown ModelType: {type}',
nameplateAddressTypes: {
Expand Down
Loading