Skip to content

Commit

Permalink
Mnes 1186 add sqlite db (#69)
Browse files Browse the repository at this point in the history
# Description

Added SQLite database and schema + seeding with prisma.

## Type of change

Please delete options that are not relevant.

-   [ ] New feature (non-breaking change which adds functionality)

# Checklist:

-   [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
-   [ ] I have made corresponding changes to the documentation
-   [ ] My changes generate no new warnings
-   [ ] I have added tests that prove my fix or my feature works
-   [ ] New and existing tests pass locally with my changes
-   [ ] My changes contain no console logs
  • Loading branch information
GailMelanie committed Aug 26, 2024
1 parent a3f4d47 commit 7530194
Show file tree
Hide file tree
Showing 16 changed files with 915 additions and 35 deletions.
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.',
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

0 comments on commit 7530194

Please sign in to comment.