add AI and cookies usage acknowledgement

This commit is contained in:
Yinyin Liu 2026-03-24 12:35:50 +01:00
parent 730f337502
commit baaabbecd0
10 changed files with 181 additions and 12 deletions

View File

@ -2309,4 +2309,17 @@ public class Controller : ControllerBase
return Ok();
}
[HttpPut(nameof(AcknowledgeTerms))]
public ActionResult AcknowledgeTerms(Int32 version, Token authToken)
{
var session = Db.GetSession(authToken);
if (session is null) return Unauthorized();
var user = Db.GetUserById(session.User.Id);
if (user is null) return Unauthorized();
user.AcknowledgedTermsVersion = version;
return Db.Update(user) ? Ok() : StatusCode(500);
}
}

View File

@ -11,6 +11,7 @@ public class User : TreeNode
public Boolean MustResetPassword { get; set; } = false;
public String? Password { get; set; } = null!;
public String Language { get; set; } = "en";
public Int32? AcknowledgedTermsVersion { get; set; }
[Unique]
public override String Name { get; set; } = null!;

View File

@ -0,0 +1,95 @@
import React from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Typography,
Divider,
Box
} from '@mui/material';
import { FormattedMessage } from 'react-intl';
export const CURRENT_TERMS_VERSION = 1;
interface AcknowledgementDialogProps {
open: boolean;
onAcknowledge: () => void;
}
const AcknowledgementDialog: React.FC<AcknowledgementDialogProps> = ({
open,
onAcknowledge
}) => {
return (
<Dialog open={open} maxWidth="sm" fullWidth>
<DialogTitle>
<FormattedMessage
id="terms_dialog_title"
defaultMessage="Welcome to inesco Energy"
/>
</DialogTitle>
<DialogContent dividers>
<Box mb={2}>
<Typography variant="subtitle1" fontWeight="bold" gutterBottom>
<FormattedMessage
id="terms_ai_heading"
defaultMessage="AI-Powered Features"
/>
</Typography>
<Typography variant="body2">
<FormattedMessage
id="terms_ai_body"
defaultMessage="This platform uses AI for diagnostics and automated analysis. AI-generated results are advisory and should be verified by qualified personnel."
/>
</Typography>
</Box>
<Divider />
<Box my={2}>
<Typography variant="subtitle1" fontWeight="bold" gutterBottom>
<FormattedMessage
id="terms_cookies_heading"
defaultMessage="Cookies and Session Storage"
/>
</Typography>
<Typography variant="body2">
<FormattedMessage
id="terms_cookies_body"
defaultMessage="Browser storage is used for login sessions and user preferences. This is required for the platform to function correctly."
/>
</Typography>
</Box>
<Divider />
<Box mt={2}>
<Typography variant="subtitle1" fontWeight="bold" gutterBottom>
<FormattedMessage
id="terms_usage_heading"
defaultMessage="Terms of Use"
/>
</Typography>
<Typography variant="body2">
<FormattedMessage
id="terms_usage_body"
defaultMessage="By using this platform, you acknowledge the general terms of use of inesco Energy. For questions, please contact your system administrator."
/>
</Typography>
</Box>
</DialogContent>
<DialogActions>
<Button variant="contained" onClick={onAcknowledge}>
<FormattedMessage
id="terms_acknowledge_button"
defaultMessage="I understand"
/>
</Button>
</DialogActions>
</Dialog>
);
};
export default AcknowledgementDialog;

View File

@ -248,9 +248,9 @@ function Log(props: LogProps) {
if (source === 'KnowledgeBase')
return <Chip label="Knowledge Base" size="small" sx={{ bgcolor: '#1976d2', color: '#fff', fontWeight: 'bold' }} />;
if (source === 'MistralAI')
return <Chip label="Mistral AI" size="small" sx={{ bgcolor: '#7b1fa2', color: '#fff', fontWeight: 'bold' }} />;
return <Chip label="AI" size="small" sx={{ bgcolor: '#7b1fa2', color: '#fff', fontWeight: 'bold' }} />;
if (source === 'MistralFailed')
return <Chip label="Mistral failed" size="small" color="error" />;
return <Chip label="AI failed" size="small" color="error" />;
return <Chip label="Not available" size="small" color="default" />;
};

View File

@ -13,6 +13,8 @@ import TreeView from '../Tree/treeView';
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
import { UserType } from '../../../interfaces/UserTypes';
import SodioHomeInstallation from './Installation';
import AcknowledgementDialog, { CURRENT_TERMS_VERSION } from '../../../components/AcknowledgementDialog';
import axiosConfig from '../../../Resources/axiosConfig';
interface SodioHomeInstallationTabsProps {
product: number;
@ -21,7 +23,25 @@ interface SodioHomeInstallationTabsProps {
function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
const location = useLocation();
const context = useContext(UserContext);
const { currentUser } = context;
const { currentUser, setUser } = context;
const showTermsDialog =
currentUser?.acknowledgedTermsVersion == null ||
currentUser.acknowledgedTermsVersion < CURRENT_TERMS_VERSION;
const handleAcknowledgeTerms = () => {
axiosConfig
.put('/AcknowledgeTerms', undefined, {
params: { version: CURRENT_TERMS_VERSION }
})
.then(() => {
const updatedUser = {
...currentUser,
acknowledgedTermsVersion: CURRENT_TERMS_VERSION
};
setUser(updatedUser);
});
};
const tabList = [
'live',
'overview',
@ -415,6 +435,10 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
return sodiohomeInstallations.length > 1 ? (
<>
<AcknowledgementDialog
open={showTermsDialog}
onAcknowledge={handleAcknowledgeTerms}
/>
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
<TabsContainerWrapper>
<Tabs
@ -483,7 +507,10 @@ function SodioHomeInstallationTabs(props: SodioHomeInstallationTabsProps) {
</>
) : sodiohomeInstallations.length === 1 ? (
<>
{' '}
<AcknowledgementDialog
open={showTermsDialog}
onAcknowledge={handleAcknowledgeTerms}
/>
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
<TabsContainerWrapper>
<Tabs

View File

@ -10,6 +10,7 @@ export type InnovEnergyUser = {
type: string;
folderIds?: number[];
mustResetPassword: boolean;
acknowledgedTermsVersion?: number;
};
export interface I_UserWithInheritedAccess {

View File

@ -204,7 +204,7 @@
"demo_test_button": "KI-Diagnose",
"demo_hide_button": "KI-Diagnose ausblenden",
"demo_panel_title": "KI-Diagnose",
"demo_custom_group": "Benutzerdefiniert (kann Mistral KI verwenden)",
"demo_custom_group": "Benutzerdefiniert (kann KI verwenden)",
"demo_custom_option": "Benutzerdefinierten Alarm eingeben…",
"demo_custom_placeholder": "z.B. UnknownBatteryFault",
"demo_diagnose_button": "Diagnostizieren",
@ -633,5 +633,13 @@
"timelineAiDiagnosisCompletedDesc": "KI-Diagnose abgeschlossen.",
"timelineAiDiagnosisFailedDesc": "KI-Diagnose fehlgeschlagen.",
"timelineEscalatedDesc": "Ticket eskaliert.",
"timelineResolutionAddedDesc": "Lösung hinzugefügt von {name}."
"timelineResolutionAddedDesc": "Lösung hinzugefügt von {name}.",
"terms_dialog_title": "Willkommen bei inesco Energy",
"terms_ai_heading": "KI-gestützte Funktionen",
"terms_ai_body": "Diese Plattform nutzt KI für Diagnosen und automatisierte Analysen. KI-generierte Ergebnisse sind beratend und sollten von qualifiziertem Personal überprüft werden.",
"terms_cookies_heading": "Cookies und Sitzungsspeicher",
"terms_cookies_body": "Browser-Speicher wird für Anmeldesitzungen und Benutzereinstellungen verwendet. Dies ist für die korrekte Funktion der Plattform erforderlich.",
"terms_usage_heading": "Nutzungsbedingungen",
"terms_usage_body": "Durch die Nutzung dieser Plattform erkennen Sie die allgemeinen Nutzungsbedingungen von inesco Energy an. Bei Fragen wenden Sie sich bitte an Ihren Systemadministrator.",
"terms_acknowledge_button": "Ich verstehe"
}

View File

@ -186,7 +186,7 @@
"demo_test_button": "AI Diagnosis",
"demo_hide_button": "Hide AI Diagnosis",
"demo_panel_title": "AI Diagnosis",
"demo_custom_group": "Custom (may use Mistral AI)",
"demo_custom_group": "Custom (may use AI)",
"demo_custom_option": "Type custom alarm below…",
"demo_custom_placeholder": "e.g. UnknownBatteryFault",
"demo_diagnose_button": "Diagnose",
@ -381,5 +381,13 @@
"timelineAiDiagnosisCompletedDesc": "AI diagnosis completed.",
"timelineAiDiagnosisFailedDesc": "AI diagnosis failed.",
"timelineEscalatedDesc": "Ticket escalated.",
"timelineResolutionAddedDesc": "Resolution added by {name}."
"timelineResolutionAddedDesc": "Resolution added by {name}.",
"terms_dialog_title": "Welcome to inesco Energy",
"terms_ai_heading": "AI-Powered Features",
"terms_ai_body": "This platform uses AI for diagnostics and automated analysis. AI-generated results are advisory and should be verified by qualified personnel.",
"terms_cookies_heading": "Cookies and Session Storage",
"terms_cookies_body": "Browser storage is used for login sessions and user preferences. This is required for the platform to function correctly.",
"terms_usage_heading": "Terms of Use",
"terms_usage_body": "By using this platform, you acknowledge the general terms of use of inesco Energy. For questions, please contact your system administrator.",
"terms_acknowledge_button": "I understand"
}

View File

@ -198,7 +198,7 @@
"demo_test_button": "Diagnostic IA",
"demo_hide_button": "Masquer le diagnostic IA",
"demo_panel_title": "Diagnostic IA",
"demo_custom_group": "Personnalisé (peut utiliser Mistral IA)",
"demo_custom_group": "Personnalisé (peut utiliser IA)",
"demo_custom_option": "Saisir une alarme personnalisée…",
"demo_custom_placeholder": "ex. UnknownBatteryFault",
"demo_diagnose_button": "Diagnostiquer",
@ -633,5 +633,13 @@
"timelineAiDiagnosisCompletedDesc": "Diagnostic IA terminé.",
"timelineAiDiagnosisFailedDesc": "Diagnostic IA échoué.",
"timelineEscalatedDesc": "Ticket escaladé.",
"timelineResolutionAddedDesc": "Résolution ajoutée par {name}."
"timelineResolutionAddedDesc": "Résolution ajoutée par {name}.",
"terms_dialog_title": "Bienvenue chez inesco Energy",
"terms_ai_heading": "Fonctionnalités basées sur l'IA",
"terms_ai_body": "Cette plateforme utilise l'IA pour les diagnostics et l'analyse automatisée. Les résultats générés par l'IA sont consultatifs et doivent être vérifiés par du personnel qualifié.",
"terms_cookies_heading": "Cookies et stockage de session",
"terms_cookies_body": "Le stockage du navigateur est utilisé pour les sessions de connexion et les préférences utilisateur. Ceci est nécessaire au bon fonctionnement de la plateforme.",
"terms_usage_heading": "Conditions d'utilisation",
"terms_usage_body": "En utilisant cette plateforme, vous reconnaissez les conditions générales d'utilisation d'inesco Energy. Pour toute question, veuillez contacter votre administrateur système.",
"terms_acknowledge_button": "Je comprends"
}

View File

@ -209,7 +209,7 @@
"demo_test_button": "Diagnosi IA",
"demo_hide_button": "Nascondi diagnosi IA",
"demo_panel_title": "Diagnosi IA",
"demo_custom_group": "Personalizzato (potrebbe usare Mistral IA)",
"demo_custom_group": "Personalizzato (potrebbe usare IA)",
"demo_custom_option": "Inserisci allarme personalizzato…",
"demo_custom_placeholder": "es. UnknownBatteryFault",
"demo_diagnose_button": "Diagnostica",
@ -633,5 +633,13 @@
"timelineAiDiagnosisCompletedDesc": "Diagnosi IA completata.",
"timelineAiDiagnosisFailedDesc": "Diagnosi IA fallita.",
"timelineEscalatedDesc": "Ticket escalato.",
"timelineResolutionAddedDesc": "Risoluzione aggiunta da {name}."
"timelineResolutionAddedDesc": "Risoluzione aggiunta da {name}.",
"terms_dialog_title": "Benvenuto su inesco Energy",
"terms_ai_heading": "Funzionalità basate sull'IA",
"terms_ai_body": "Questa piattaforma utilizza l'IA per la diagnostica e l'analisi automatizzata. I risultati generati dall'IA sono a scopo consultivo e devono essere verificati da personale qualificato.",
"terms_cookies_heading": "Cookie e archiviazione sessione",
"terms_cookies_body": "L'archiviazione del browser viene utilizzata per le sessioni di accesso e le preferenze utente. Questo è necessario per il corretto funzionamento della piattaforma.",
"terms_usage_heading": "Condizioni d'uso",
"terms_usage_body": "Utilizzando questa piattaforma, si riconoscono le condizioni generali d'uso di inesco Energy. Per domande, contattare l'amministratore di sistema.",
"terms_acknowledge_button": "Ho capito"
}