Téléverser les fichiers vers "first-login-ui/src"
This commit is contained in:
+278
-95
@@ -19,18 +19,53 @@ Kirigami.ApplicationWindow {
|
||||
{ "title": "Terminé", "subtitle": "Poste prêt" }
|
||||
]
|
||||
|
||||
property bool passwordStepValid:
|
||||
currentPassword.text.trim().length > 0 &&
|
||||
newPassword.text.length > 0 &&
|
||||
confirmPassword.text.length > 0 &&
|
||||
newPassword.text === confirmPassword.text
|
||||
|
||||
property bool pinStepValid:
|
||||
currentPin.text.length >= 4 &&
|
||||
newPin.text.length >= 4 &&
|
||||
confirmPin.text.length >= 4 &&
|
||||
newPin.text === confirmPin.text
|
||||
|
||||
property bool workflowComplete: passwordStepValid && pinStepValid
|
||||
property bool closeAttempted: false
|
||||
|
||||
function goNext() {
|
||||
if (currentStep < steps.length - 1) {
|
||||
// Défense en profondeur : même si un bouton était activé par erreur,
|
||||
// on ne franchit jamais une étape dont les champs requis sont incomplets.
|
||||
if (currentStep === 1 && !passwordStepValid)
|
||||
return
|
||||
if (currentStep === 2 && !pinStepValid)
|
||||
return
|
||||
|
||||
if (currentStep < steps.length - 1)
|
||||
currentStep += 1
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
if (currentStep > 0) {
|
||||
if (currentStep > 0)
|
||||
currentStep -= 1
|
||||
}
|
||||
|
||||
onClosing: function(close) {
|
||||
if (!workflowComplete) {
|
||||
close.accepted = false
|
||||
closeAttempted = true
|
||||
closeWarningTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: closeWarningTimer
|
||||
interval: 3500
|
||||
repeat: false
|
||||
onTriggered: root.closeAttempted = false
|
||||
}
|
||||
|
||||
// Indicateur volontairement informatif : il ne bloque jamais
|
||||
// la validation du mot de passe. La longueur est privilégiée,
|
||||
// la diversité des caractères apporte un bonus visuel.
|
||||
@@ -89,11 +124,6 @@ Kirigami.ApplicationWindow {
|
||||
return "Saisissez votre nouveau mot de passe pour obtenir une indication de robustesse."
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Ctrl+Q"
|
||||
onActivated: Qt.quit()
|
||||
}
|
||||
|
||||
component PrimaryButton: Controls.Button {
|
||||
id: control
|
||||
implicitHeight: 48
|
||||
@@ -196,6 +226,29 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
component FieldLabel: RowLayout {
|
||||
id: fieldLabel
|
||||
|
||||
property string iconName: "dialog-password"
|
||||
property string labelText: ""
|
||||
|
||||
spacing: 8
|
||||
|
||||
Kirigami.Icon {
|
||||
source: fieldLabel.iconName
|
||||
implicitWidth: 17
|
||||
implicitHeight: 17
|
||||
color: "#64748b"
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: fieldLabel.labelText
|
||||
color: "#334155"
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
||||
|
||||
component StepDot: Rectangle {
|
||||
required property int stepIndex
|
||||
|
||||
@@ -301,37 +354,49 @@ Kirigami.ApplicationWindow {
|
||||
anchors.fill: parent
|
||||
spacing: 16
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
spacing: 0
|
||||
// Colonne de largeur fixe : tous les marqueurs et tous
|
||||
// les titres commencent exactement au même endroit.
|
||||
Item {
|
||||
Layout.preferredWidth: 42
|
||||
Layout.fillHeight: true
|
||||
|
||||
StepDot { stepIndex: index }
|
||||
StepDot {
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
stepIndex: index
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: index < root.steps.length - 1
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: 2
|
||||
Layout.preferredHeight: 36
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 34
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 2
|
||||
color: index < root.currentStep ? "#22c55e" : "#28517e"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 3
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData.title
|
||||
color: index === root.currentStep ? "white" : "#c1d3e8"
|
||||
font.pixelSize: 15
|
||||
font.weight: index === root.currentStep ? Font.DemiBold : Font.Medium
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData.subtitle
|
||||
color: "#7699c2"
|
||||
font.pixelSize: 12
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,11 +447,22 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
Item { Layout.preferredHeight: 20 }
|
||||
|
||||
Controls.Label {
|
||||
text: "Ctrl+Q : quitter l'aperçu"
|
||||
color: "#6289b6"
|
||||
font.pixelSize: 11
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 6
|
||||
|
||||
Kirigami.Icon {
|
||||
source: "lock"
|
||||
implicitWidth: 14
|
||||
implicitHeight: 14
|
||||
color: "#6289b6"
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: "Assistant obligatoire jusqu'à la fin"
|
||||
color: "#6289b6"
|
||||
font.pixelSize: 11
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,9 +507,37 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
SecondaryButton {
|
||||
text: "Quitter l'aperçu"
|
||||
onClicked: Qt.quit()
|
||||
Rectangle {
|
||||
implicitWidth: lockStatusRow.implicitWidth + 24
|
||||
implicitHeight: 34
|
||||
radius: 17
|
||||
color: root.closeAttempted ? "#fef2f2" : "#f8fafc"
|
||||
border.width: 1
|
||||
border.color: root.closeAttempted ? "#fecaca" : "#cbd5e1"
|
||||
|
||||
RowLayout {
|
||||
id: lockStatusRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 7
|
||||
|
||||
Kirigami.Icon {
|
||||
source: root.workflowComplete ? "lock-open" : "lock"
|
||||
implicitWidth: 16
|
||||
implicitHeight: 16
|
||||
color: root.closeAttempted ? "#dc2626" : "#64748b"
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: root.closeAttempted
|
||||
? "Terminez la configuration avant de quitter"
|
||||
: root.workflowComplete
|
||||
? "Configuration complète"
|
||||
: "Configuration en cours"
|
||||
color: root.closeAttempted ? "#b91c1c" : "#475569"
|
||||
font.pixelSize: 11
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,20 +701,47 @@ Kirigami.ApplicationWindow {
|
||||
anchors.fill: parent
|
||||
spacing: 18
|
||||
|
||||
Controls.Label {
|
||||
text: "Mot de passe local"
|
||||
color: "#0f172a"
|
||||
font.pixelSize: 29
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 20
|
||||
|
||||
Controls.Label {
|
||||
Layout.maximumWidth: 720
|
||||
text: "Ce mot de passe reste disponible comme solution de secours si votre YubiKey est momentanément indisponible."
|
||||
wrapMode: Text.WordWrap
|
||||
color: "#64748b"
|
||||
font.pixelSize: 15
|
||||
lineHeight: 1.2
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 80
|
||||
Layout.preferredHeight: 80
|
||||
radius: 22
|
||||
color: "#eff6ff"
|
||||
border.width: 1
|
||||
border.color: "#bfdbfe"
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
source: "dialog-password"
|
||||
implicitWidth: 38
|
||||
implicitHeight: 38
|
||||
color: "#2563eb"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 5
|
||||
|
||||
Controls.Label {
|
||||
text: "Mot de passe local"
|
||||
color: "#0f172a"
|
||||
font.pixelSize: 29
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Ce mot de passe reste disponible comme solution de secours si votre YubiKey est momentanément indisponible."
|
||||
wrapMode: Text.WordWrap
|
||||
color: "#64748b"
|
||||
font.pixelSize: 15
|
||||
lineHeight: 1.2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -626,11 +757,11 @@ Kirigami.ApplicationWindow {
|
||||
anchors.margins: 16
|
||||
spacing: 12
|
||||
|
||||
Controls.Label {
|
||||
text: "ℹ"
|
||||
Kirigami.Icon {
|
||||
source: "emblem-information"
|
||||
implicitWidth: 22
|
||||
implicitHeight: 22
|
||||
color: "#2563eb"
|
||||
font.pixelSize: 22
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
@@ -645,11 +776,9 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
Item { Layout.preferredHeight: 4 }
|
||||
|
||||
Controls.Label {
|
||||
text: "Mot de passe temporaire actuel"
|
||||
color: "#334155"
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
FieldLabel {
|
||||
iconName: "dialog-password"
|
||||
labelText: "Mot de passe temporaire actuel"
|
||||
}
|
||||
|
||||
SecretField {
|
||||
@@ -657,11 +786,9 @@ Kirigami.ApplicationWindow {
|
||||
placeholderText: "Saisissez le mot de passe temporaire"
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: "Nouveau mot de passe"
|
||||
color: "#334155"
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
FieldLabel {
|
||||
iconName: "document-edit"
|
||||
labelText: "Nouveau mot de passe"
|
||||
}
|
||||
|
||||
SecretField {
|
||||
@@ -690,6 +817,14 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Kirigami.Icon {
|
||||
source: "security-high"
|
||||
implicitWidth: 17
|
||||
implicitHeight: 17
|
||||
color: root.passwordStrengthColor(strengthCard.strengthLevel)
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: "Robustesse du mot de passe"
|
||||
@@ -747,11 +882,9 @@ Kirigami.ApplicationWindow {
|
||||
font.pixelSize: 11
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: "Confirmation"
|
||||
color: "#334155"
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
FieldLabel {
|
||||
iconName: "dialog-ok-apply"
|
||||
labelText: "Confirmation"
|
||||
}
|
||||
|
||||
SecretField {
|
||||
@@ -780,7 +913,7 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
PrimaryButton {
|
||||
text: "Continuer"
|
||||
enabled: newPassword.text.length > 0 && newPassword.text === confirmPassword.text
|
||||
enabled: root.passwordStepValid
|
||||
opacity: enabled ? 1.0 : 0.45
|
||||
onClicked: root.goNext()
|
||||
}
|
||||
@@ -865,11 +998,9 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: "PIN temporaire actuel"
|
||||
color: "#334155"
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
FieldLabel {
|
||||
iconName: "dialog-password"
|
||||
labelText: "PIN temporaire actuel"
|
||||
}
|
||||
|
||||
SecretField {
|
||||
@@ -878,11 +1009,9 @@ Kirigami.ApplicationWindow {
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: "Nouveau PIN"
|
||||
color: "#334155"
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
FieldLabel {
|
||||
iconName: "security-high"
|
||||
labelText: "Nouveau PIN"
|
||||
}
|
||||
|
||||
SecretField {
|
||||
@@ -891,11 +1020,9 @@ Kirigami.ApplicationWindow {
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: "Confirmation du nouveau PIN"
|
||||
color: "#334155"
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
FieldLabel {
|
||||
iconName: "dialog-ok-apply"
|
||||
labelText: "Confirmation du nouveau PIN"
|
||||
}
|
||||
|
||||
SecretField {
|
||||
@@ -925,7 +1052,7 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
PrimaryButton {
|
||||
text: "Finaliser"
|
||||
enabled: newPin.text.length >= 4 && newPin.text === confirmPin.text
|
||||
enabled: root.pinStepValid
|
||||
opacity: enabled ? 1.0 : 0.45
|
||||
onClicked: root.goNext()
|
||||
}
|
||||
@@ -952,12 +1079,12 @@ Kirigami.ApplicationWindow {
|
||||
border.width: 1
|
||||
border.color: "#86efac"
|
||||
|
||||
Controls.Label {
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
text: "✓"
|
||||
source: "dialog-ok-apply"
|
||||
implicitWidth: 52
|
||||
implicitHeight: 52
|
||||
color: "#16a34a"
|
||||
font.pixelSize: 50
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,28 +1110,82 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
Item { Layout.preferredHeight: 12 }
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 520
|
||||
Layout.preferredHeight: 112
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
radius: 16
|
||||
color: "#f8fafc"
|
||||
border.width: 1
|
||||
border.color: "#e2e8f0"
|
||||
spacing: 12
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 18
|
||||
spacing: 10
|
||||
Repeater {
|
||||
model: [
|
||||
{ "icon": "dialog-password", "title": "Mot de passe", "text": "Accès local renseigné" },
|
||||
{ "icon": "security-high", "title": "YubiKey", "text": "PIN personnel renseigné" },
|
||||
{ "icon": "computer-laptop", "title": "Poste", "text": "Configuration finalisée" }
|
||||
]
|
||||
|
||||
RowLayout {
|
||||
Controls.Label { text: "✓"; color: "#16a34a"; font.pixelSize: 17; font.weight: Font.Bold }
|
||||
Controls.Label { text: "Mot de passe personnel configuré"; color: "#334155"; font.pixelSize: 14 }
|
||||
}
|
||||
Rectangle {
|
||||
required property var modelData
|
||||
Layout.preferredWidth: 205
|
||||
Layout.preferredHeight: 126
|
||||
radius: 16
|
||||
color: "#f8fafc"
|
||||
border.width: 1
|
||||
border.color: "#e2e8f0"
|
||||
|
||||
RowLayout {
|
||||
Controls.Label { text: "✓"; color: "#16a34a"; font.pixelSize: 17; font.weight: Font.Bold }
|
||||
Controls.Label { text: "PIN personnel YubiKey configuré"; color: "#334155"; font.pixelSize: 14 }
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 7
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 38
|
||||
Layout.preferredHeight: 38
|
||||
radius: 11
|
||||
color: "#eff6ff"
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
source: modelData.icon
|
||||
implicitWidth: 21
|
||||
implicitHeight: 21
|
||||
color: "#2563eb"
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 25
|
||||
Layout.preferredHeight: 25
|
||||
radius: 13
|
||||
color: "#dcfce7"
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
source: "dialog-ok-apply"
|
||||
implicitWidth: 15
|
||||
implicitHeight: 15
|
||||
color: "#16a34a"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
text: modelData.title
|
||||
color: "#0f172a"
|
||||
font.pixelSize: 14
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData.text
|
||||
color: "#64748b"
|
||||
font.pixelSize: 11
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1021,7 +1202,9 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
|
||||
PrimaryButton {
|
||||
text: "Fermer l'aperçu"
|
||||
text: "Terminer"
|
||||
enabled: root.workflowComplete
|
||||
opacity: enabled ? 1.0 : 0.45
|
||||
onClicked: Qt.quit()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user