Compare commits

...

8 Commits

Author SHA1 Message Date
BuildTools
af867d248d Warnings entfernt 2024-02-28 19:54:09 +01:00
BuildTools
2ad3da8b20 Pages auf Englisch umbenannt 2024-02-28 19:53:53 +01:00
BuildTools
67ae87b78d Aktueller Datenstand 2024-02-28 19:52:57 +01:00
BuildTools
7718d893cc Filler Angepasst - Pos gilt jetzt pro Typ 2024-02-28 19:52:39 +01:00
BuildTools
6a1dfb0e4f Ersteller und Counter zu Cocktail-Klasse hinzugefügt 2024-02-28 19:51:38 +01:00
BuildTools
5331a1c9d1 Passwortdialog für Einstellungen eingebaut 2024-02-28 19:50:42 +01:00
BuildTools
7ee75d0de3 Flaschen bearbeiten auf Extra Form gepackt 2024-02-28 19:49:59 +01:00
BuildTools
ccb0404477 Code u. Page zusammengefasst 2024-02-28 19:48:20 +01:00
27 changed files with 1256 additions and 269 deletions

View File

@ -3,8 +3,14 @@
public class Cocktail
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Name { get; set; } = null!;
public string? Ersteller { get; set; }
public string? ImageURL { get; set; }
public int Counter { get; set; }
public List<CocktailFlasche> Cocktailflaschen { get; set; } = new();
}
}

View File

@ -6,8 +6,8 @@
public int Id { get; set; }
public int CocktailID { get; set; }
public int FlascheID { get; set; }
public Flasche Flasche { get; set; }
public Cocktail Cocktail { get; set; }
public Flasche Flasche { get; set; } = null!;
public Cocktail Cocktail { get; set; } = null!;
public int Reihenfolge { get; set; }
public int Menge { get; set; }

View File

@ -35,18 +35,20 @@ namespace CocktailWeb.Data
new Filler() { Id = 1, Pos = 1, Type = Filler.FillerType.Pump },
new Filler() { Id = 2, Pos = 2, Type = Filler.FillerType.Pump },
new Filler() { Id = 3, Pos = 3, Type = Filler.FillerType.Pump },
new Filler() { Id = 4, Pos = 4, Type = Filler.FillerType.Pourer },
new Filler() { Id = 5, Pos = 5, Type = Filler.FillerType.Pourer },
new Filler() { Id = 6, Pos = 6, Type = Filler.FillerType.Pourer },
new Filler() { Id = 7, Pos = 7, Type = Filler.FillerType.Pourer },
new Filler() { Id = 8, Pos = 8, Type = Filler.FillerType.Pourer },
new Filler() { Id = 9, Pos = 9, Type = Filler.FillerType.Pourer },
new Filler() { Id = 10, Pos = 10, Type = Filler.FillerType.Pourer },
new Filler() { Id = 11, Pos = 11, Type = Filler.FillerType.Pourer },
new Filler() { Id = 12, Pos = 12, Type = Filler.FillerType.Pump },
new Filler() { Id = 13, Pos = 13, Type = Filler.FillerType.Pump },
new Filler() { Id = 14, Pos = 14, Type = Filler.FillerType.Pump }
new Filler() { Id = 4, Pos = 1, Type = Filler.FillerType.Pourer },
new Filler() { Id = 5, Pos = 2, Type = Filler.FillerType.Pourer },
new Filler() { Id = 6, Pos = 3, Type = Filler.FillerType.Pourer },
new Filler() { Id = 7, Pos = 4, Type = Filler.FillerType.Pourer },
new Filler() { Id = 8, Pos = 5, Type = Filler.FillerType.Pourer },
new Filler() { Id = 9, Pos = 6, Type = Filler.FillerType.Pourer },
new Filler() { Id = 10, Pos = 7, Type = Filler.FillerType.Pourer },
new Filler() { Id = 11, Pos = 8, Type = Filler.FillerType.Pourer },
new Filler() { Id = 12, Pos = 4, Type = Filler.FillerType.Pump },
new Filler() { Id = 13, Pos = 5, Type = Filler.FillerType.Pump },
new Filler() { Id = 14, Pos = 6, Type = Filler.FillerType.Pump }
);
modelBuilder.Entity<Filler>().HasIndex(p => new {p.Type, p.Pos}).IsUnique();
modelBuilder.Entity<Glas>().ToTable("Glaeser");

Binary file not shown.

View File

@ -9,5 +9,7 @@
public string SerialPort { get; set; } = "COM5";
public int Baudrate { get; set; } = 115200;
public string? SettingsPassword { get; set; }
}
}

View File

@ -0,0 +1,269 @@
// <auto-generated />
using System;
using CocktailWeb.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace CocktailWeb.Migrations
{
[DbContext(typeof(DbDataContext))]
[Migration("20240228182043_ModifyCocktailAddErstellerCounter")]
partial class ModifyCocktailAddErstellerCounter
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.1");
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Counter")
.HasColumnType("INTEGER");
b.Property<string>("Ersteller")
.HasColumnType("TEXT");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Cocktails");
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CocktailID")
.HasColumnType("INTEGER");
b.Property<int>("FlascheID")
.HasColumnType("INTEGER");
b.Property<int>("Menge")
.HasColumnType("INTEGER");
b.Property<int>("Reihenfolge")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CocktailID");
b.HasIndex("FlascheID");
b.ToTable("CocktailFlaschen");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("FlascheId")
.HasColumnType("INTEGER");
b.Property<int>("Pos")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("FlascheId");
b.ToTable("Fillers");
b.HasData(
new
{
Id = 1,
Pos = 1,
Type = 0
},
new
{
Id = 2,
Pos = 2,
Type = 0
},
new
{
Id = 3,
Pos = 3,
Type = 0
},
new
{
Id = 4,
Pos = 4,
Type = 1
},
new
{
Id = 5,
Pos = 5,
Type = 1
},
new
{
Id = 6,
Pos = 6,
Type = 1
},
new
{
Id = 7,
Pos = 7,
Type = 1
},
new
{
Id = 8,
Pos = 8,
Type = 1
},
new
{
Id = 9,
Pos = 9,
Type = 1
},
new
{
Id = 10,
Pos = 10,
Type = 1
},
new
{
Id = 11,
Pos = 11,
Type = 1
},
new
{
Id = 12,
Pos = 12,
Type = 0
},
new
{
Id = 13,
Pos = 13,
Type = 0
},
new
{
Id = 14,
Pos = 14,
Type = 0
});
});
modelBuilder.Entity("CocktailWeb.Data.Flasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Alkoholisch")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Flaschen", (string)null);
b.HasData(
new
{
Id = 1,
Alkoholisch = true,
Name = "Jägermeister"
},
new
{
Id = 2,
Alkoholisch = true,
Name = "Wodka"
});
});
modelBuilder.Entity("CocktailWeb.Data.Glas", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Fuellmenge")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Glaeser", (string)null);
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.HasOne("CocktailWeb.Data.Cocktail", "Cocktail")
.WithMany("Cocktailflaschen")
.HasForeignKey("CocktailID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Cocktail");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheId");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Navigation("Cocktailflaschen");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CocktailWeb.Migrations
{
/// <inheritdoc />
public partial class ModifyCocktailAddErstellerCounter : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Counter",
table: "Cocktails",
type: "INTEGER",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<string>(
name: "Ersteller",
table: "Cocktails",
type: "TEXT",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Counter",
table: "Cocktails");
migrationBuilder.DropColumn(
name: "Ersteller",
table: "Cocktails");
}
}
}

View File

@ -0,0 +1,272 @@
// <auto-generated />
using System;
using CocktailWeb.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace CocktailWeb.Migrations
{
[DbContext(typeof(DbDataContext))]
[Migration("20240228183936_ModiyFillerUniquePosType")]
partial class ModiyFillerUniquePosType
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.1");
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Counter")
.HasColumnType("INTEGER");
b.Property<string>("Ersteller")
.HasColumnType("TEXT");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Cocktails");
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CocktailID")
.HasColumnType("INTEGER");
b.Property<int>("FlascheID")
.HasColumnType("INTEGER");
b.Property<int>("Menge")
.HasColumnType("INTEGER");
b.Property<int>("Reihenfolge")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CocktailID");
b.HasIndex("FlascheID");
b.ToTable("CocktailFlaschen");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("FlascheId")
.HasColumnType("INTEGER");
b.Property<int>("Pos")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("FlascheId");
b.HasIndex("Type", "Pos")
.IsUnique();
b.ToTable("Fillers");
b.HasData(
new
{
Id = 1,
Pos = 1,
Type = 0
},
new
{
Id = 2,
Pos = 2,
Type = 0
},
new
{
Id = 3,
Pos = 3,
Type = 0
},
new
{
Id = 4,
Pos = 1,
Type = 1
},
new
{
Id = 5,
Pos = 2,
Type = 1
},
new
{
Id = 6,
Pos = 3,
Type = 1
},
new
{
Id = 7,
Pos = 4,
Type = 1
},
new
{
Id = 8,
Pos = 5,
Type = 1
},
new
{
Id = 9,
Pos = 6,
Type = 1
},
new
{
Id = 10,
Pos = 7,
Type = 1
},
new
{
Id = 11,
Pos = 8,
Type = 1
},
new
{
Id = 12,
Pos = 4,
Type = 0
},
new
{
Id = 13,
Pos = 5,
Type = 0
},
new
{
Id = 14,
Pos = 6,
Type = 0
});
});
modelBuilder.Entity("CocktailWeb.Data.Flasche", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Alkoholisch")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Flaschen", (string)null);
b.HasData(
new
{
Id = 1,
Alkoholisch = true,
Name = "Jägermeister"
},
new
{
Id = 2,
Alkoholisch = true,
Name = "Wodka"
});
});
modelBuilder.Entity("CocktailWeb.Data.Glas", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Fuellmenge")
.HasColumnType("INTEGER");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Glaeser", (string)null);
});
modelBuilder.Entity("CocktailWeb.Data.CocktailFlasche", b =>
{
b.HasOne("CocktailWeb.Data.Cocktail", "Cocktail")
.WithMany("Cocktailflaschen")
.HasForeignKey("CocktailID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Cocktail");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Filler", b =>
{
b.HasOne("CocktailWeb.Data.Flasche", "Flasche")
.WithMany()
.HasForeignKey("FlascheId");
b.Navigation("Flasche");
});
modelBuilder.Entity("CocktailWeb.Data.Cocktail", b =>
{
b.Navigation("Cocktailflaschen");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,182 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CocktailWeb.Migrations
{
/// <inheritdoc />
public partial class ModiyFillerUniquePosType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 4,
column: "Pos",
value: 1);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 5,
column: "Pos",
value: 2);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 6,
column: "Pos",
value: 3);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 7,
column: "Pos",
value: 4);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 8,
column: "Pos",
value: 5);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 9,
column: "Pos",
value: 6);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 10,
column: "Pos",
value: 7);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 11,
column: "Pos",
value: 8);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 12,
column: "Pos",
value: 4);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 13,
column: "Pos",
value: 5);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 14,
column: "Pos",
value: 6);
migrationBuilder.CreateIndex(
name: "IX_Fillers_Type_Pos",
table: "Fillers",
columns: new[] { "Type", "Pos" },
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Fillers_Type_Pos",
table: "Fillers");
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 4,
column: "Pos",
value: 4);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 5,
column: "Pos",
value: 5);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 6,
column: "Pos",
value: 6);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 7,
column: "Pos",
value: 7);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 8,
column: "Pos",
value: 8);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 9,
column: "Pos",
value: 9);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 10,
column: "Pos",
value: 10);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 11,
column: "Pos",
value: 11);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 12,
column: "Pos",
value: 12);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 13,
column: "Pos",
value: 13);
migrationBuilder.UpdateData(
table: "Fillers",
keyColumn: "Id",
keyValue: 14,
column: "Pos",
value: 14);
}
}
}

View File

@ -23,6 +23,12 @@ namespace CocktailWeb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Counter")
.HasColumnType("INTEGER");
b.Property<string>("Ersteller")
.HasColumnType("TEXT");
b.Property<string>("ImageURL")
.HasColumnType("TEXT");
@ -81,6 +87,9 @@ namespace CocktailWeb.Migrations
b.HasIndex("FlascheId");
b.HasIndex("Type", "Pos")
.IsUnique();
b.ToTable("Fillers");
b.HasData(
@ -105,67 +114,67 @@ namespace CocktailWeb.Migrations
new
{
Id = 4,
Pos = 4,
Pos = 1,
Type = 1
},
new
{
Id = 5,
Pos = 5,
Pos = 2,
Type = 1
},
new
{
Id = 6,
Pos = 6,
Pos = 3,
Type = 1
},
new
{
Id = 7,
Pos = 7,
Pos = 4,
Type = 1
},
new
{
Id = 8,
Pos = 8,
Pos = 5,
Type = 1
},
new
{
Id = 9,
Pos = 9,
Pos = 6,
Type = 1
},
new
{
Id = 10,
Pos = 10,
Pos = 7,
Type = 1
},
new
{
Id = 11,
Pos = 11,
Pos = 8,
Type = 1
},
new
{
Id = 12,
Pos = 12,
Pos = 4,
Type = 0
},
new
{
Id = 13,
Pos = 13,
Pos = 5,
Type = 0
},
new
{
Id = 14,
Pos = 14,
Pos = 6,
Type = 0
});
});

View File

@ -23,7 +23,7 @@
bool Sending = false;
bool Receiving = false;
public async Task SendData()
public void SendData()
{
if (Sending) return; // nichts senden, wenn bereits am Senden
Sending = true;

View File

@ -16,13 +16,26 @@
<div class="d-flex gap-3">
<div class="border border-2 rounded p-3 w-100">
<h4>Mein Cocktail</h4>
<div class="mb-3">
<label class="form-label" for="cocktailname">Cocktailname</label>
<input id="cocktailname" name="cocktailname" type="text" class="form-control" @bind="@EditCocktail.Name" />
</div>
<div class="mb-3">
<label class="form-label" for="ersteller">Ersteller</label>
<input id="ersteller" name="ersteller" type="text" class="form-control" @bind="@EditCocktail.Ersteller" />
</div>
<div class="mb-3">
<label class="form-label" for="cocktailimage">Bild</label>
<div class="mb-2">
@if (EditCocktail.ImageURL != null)
{
<img style="max-width:128px;" src="@EditCocktail.ImageURL" />
} else
{
<div>Kein Bild vorhanden</div>
}
</div>
<label class="form-label" for="cocktailimage">Neues Bild hochladen</label>
<InputFile OnChange="Bild_OnChange" class="form-control" id="cocktailimage" name="cocktailimage" accept=".jpg,.png,.jpeg,.gif,.webp" />
</div>
@ -44,18 +57,18 @@
<th>@cf.Flasche.Name</th>
<td>
<div class="input-group">
<input class="form-control" id="Menge" name="menge" type="text" @bind="@cf.Menge" />
<input class="form-control" id="Menge" name="menge" type="number" @bind="@cf.Menge" />
<span class="input-group-text">ml</span>
</div>
</td>
<td>
<div class="btn-group">
<button class="btn btn-outline-secondary" @onclick="args => FlascheReihenfolge(args, cf,-2)">
<button class="btn btn-outline-primary" @onclick="args => FlascheReihenfolge(args, cf,-2)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-up-fill" viewBox="0 0 16 16">
<path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z" />
</svg>
</button>
<button class="btn btn-outline-secondary" @onclick="args => FlascheReihenfolge(args, cf ,2)">
<button class="btn btn-outline-primary" @onclick="args => FlascheReihenfolge(args, cf ,2)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16">
<path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z" />
</svg>
@ -72,6 +85,12 @@
</td>
</tr>
}
<tr>
<th></th>
<th>Gesamt</th>
<td>@EditCocktail.Cocktailflaschen.Sum(cf => cf.Menge)</td>
<td colspan="2"></td>
</tr>
}
</tbody>
</table>
@ -92,7 +111,7 @@
{
@foreach (Flasche fl in FlaschenListe)
{
<li class="list-group-item list-group-item-action align-middle" @onclick="args => FlascheHinzufuegen(args,fl)">
<li class="list-group-item list-group-item-action align-middle z-0" @onclick="args => FlascheHinzufuegen(args,fl)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-circle text-success" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16" />
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4" />

View File

@ -6,13 +6,13 @@ using Microsoft.EntityFrameworkCore;
namespace CocktailWeb.Pages.Settings
{
public partial class CocktailHinzufuegen
public partial class CocktailEdit
{
[Parameter]
public string? id { get; set; }
public List<Flasche> FlaschenListe { get; set; } = new();
public Cocktail? EditCocktail;
public Cocktail EditCocktail = null!;
private IBrowserFile? CocktaiLBildDatei;
private DbDataContext? _DataContext;
@ -104,7 +104,7 @@ namespace CocktailWeb.Pages.Settings
try
{
// Bild hochladen
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"{EditCocktail.Id}{Path.GetExtension(CocktaiLBildDatei.Name)}");
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"cocktail_{EditCocktail.Id}{Path.GetExtension(CocktaiLBildDatei.Name)}");
var fullpath = Path.Join(env.WebRootPath, relativeuploadpath);
string? folder = Path.GetDirectoryName(fullpath);
if (folder != null && !Path.Exists(folder)) Directory.CreateDirectory(folder);

View File

@ -21,7 +21,7 @@
<tr>
<td class="p-0" style="width:64px"><img src="@c.ImageURL" style="max-width:100%; max-height:auto;" /></td>
<td style="vertical-align:middle;">@c.Name</td>
<td style="text-align:right; vertical-align:middle;" >
<td style="text-align:right; vertical-align:middle;">
<a class="btn btn-primary" href="/settings/cocktails/edit/@c.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDelete(c)">Löschen</button>
</td>
@ -41,4 +41,52 @@
<button class="btn btn-danger" @onclick="DeleteCocktail">Jo</button>
<button class="btn btn-primary" @onclick="CloseDialog">Nee</button>
</Footer>
</ModalComponent>
</ModalComponent>
@code {
private DbDataContext? _DataContext;
private ModalComponent modal = null!;
private Cocktail? SelectedCocktail;
private List<Cocktail> CocktailListe { get; set; } = new();
protected override async Task OnInitializedAsync()
{
await ShowCocktails();
}
private async Task ShowCocktails()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
CocktailListe = await _DataContext.Cocktails.OrderBy(f => f.Name).ToListAsync();
}
}
private async Task ConfirmDelete(Cocktail c)
{
SelectedCocktail = c;
await modal.OpenModal();
}
private async Task CloseDialog()
{
SelectedCocktail = null;
await modal.Close();
}
private async Task DeleteCocktail(MouseEventArgs e)
{
if (SelectedCocktail != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
_DataContext.Cocktails.Remove(SelectedCocktail);
await _DataContext.SaveChangesAsync();
await ShowCocktails();
}
}
await CloseDialog();
}
}

View File

@ -1,58 +0,0 @@
using CocktailWeb;
using CocktailWeb.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.EntityFrameworkCore;
namespace CocktailWeb.Pages.Settings
{
public partial class Cocktails
{
private DbDataContext? _DataContext;
private ModalComponent modal = null!;
private Cocktail? SelectedCocktail;
private List<Cocktail> CocktailListe { get; set; } = new();
protected override async Task OnInitializedAsync()
{
await ShowCocktails();
}
private async Task ShowCocktails()
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
CocktailListe = await _DataContext.Cocktails.OrderBy(f => f.Name).ToListAsync();
}
}
private async Task ConfirmDelete(Cocktail c)
{
SelectedCocktail = c;
await modal.OpenModal();
}
private async Task CloseDialog()
{
SelectedCocktail = null;
await modal.Close();
}
private async Task DeleteCocktail(MouseEventArgs e)
{
if (SelectedCocktail != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
_DataContext.Cocktails.Remove(SelectedCocktail);
await _DataContext.SaveChangesAsync();
await ShowCocktails();
}
}
await CloseDialog();
}
}
}

View File

@ -1,73 +0,0 @@
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using CocktailWeb.Data
@page "/settings/flaschen"
@inject IDbContextFactory<DbDataContext> FlascheDataContextFactory;
<PageTitle>Flaschen</PageTitle>
<SectionContent SectionId="TopRow.Title">
<label>Einstellungen - Zutaten</label>
</SectionContent>
@if (CreateFormVisible && FlascheToCreate != null)
{
<h3>Flasche hinzufügen</h3>
<div class="row">
<label for="Name" class="col-4 col-form-label">Name</label>
<div class="col-8">
<input id="Name" name="Name" type="text" class="form-control" @bind="@FlascheToCreate.Name" />
</div>
</div>
<div class="form-group row">
<div class="offset-4 col-8">
<button name="submit" type="submit" class="btn btn-primary" @onclick="CreateNewFlasche">Hinzufügen</button>
</div>
</div>
}
else
{
<button name="submit" type="submit" class="btn btn-primary" @onclick="ShowCreateForm">Flasche hinzufügen</button>
}
@if (FlaschenListe != null && FlaschenListe.Count > 0)
{
<div class="table-responsive mt-3">
<table class="table table-striped table-hover table-bordered table-dark border-dark">
<thead>
<tr>
<th scope="col">Name</th>
<th style="text-align:right;" scope="col">Action</th>
</tr>
</thead>
<tbody>
@foreach (var flasche in FlaschenListe)
{
@if (EditFormVisible && FlascheToUpdate != null && FlascheToUpdate.Id == flasche.Id)
{
<tr>
<td> <input id="Name" name="Name" type="text" class="form-control" @bind="@FlascheToUpdate.Name" /></td>
<td><button name="submit" type="submit" class="btn btn-primary" @onclick="() => UpdateEmployee(FlascheToUpdate)">Speichern</button></td>
</tr>
}
else
{
<tr>
<td>@flasche.Name</td>
<td style="text-align:right;">
<button name="submit" type="submit" class="btn btn-primary" @onclick="() => ShowEditForm(flasche)">Bearbeiten</button>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => DeleteFlasche(flasche)">Löschen</button>
</td>
</tr>
}
}
</tbody>
</table>
</div>
}
@code {
}

View File

@ -1,84 +0,0 @@
using SQLitePCL;
using Microsoft.EntityFrameworkCore;
using CocktailWeb.Data;
namespace CocktailWeb.Pages.Settings
{
public partial class Flaschen
{
public bool CreateFormVisible { get; set; }
public bool EditFormVisible { get; set; }
public Flasche? FlascheToCreate { get; set; }
public Flasche? FlascheToUpdate { get; set; }
public List<Flasche>? FlaschenListe { get; set; }
private DbDataContext? _DataContext;
protected override async Task OnInitializedAsync()
{
CreateFormVisible = false;
await ShowFlaschen();
}
public void ShowCreateForm()
{
FlascheToCreate = new Flasche();
CreateFormVisible = true;
}
public async Task CreateNewFlasche()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (FlascheToCreate != null && _DataContext != null)
{
_DataContext.Flaschen.Add(FlascheToCreate);
await _DataContext.SaveChangesAsync();
}
CreateFormVisible = false;
await ShowFlaschen();
}
public async Task ShowFlaschen()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
FlaschenListe = await _DataContext.Flaschen.OrderBy(f => f.Name).ToListAsync();
}
}
public async Task ShowEditForm(Flasche flasche)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
FlascheToUpdate = _DataContext.Flaschen.FirstOrDefault(f => f.Id == flasche.Id);
EditFormVisible = true;
}
public async Task UpdateEmployee(Flasche flasche)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null && flasche != null)
{
_DataContext.Flaschen.Update(flasche);
await _DataContext.SaveChangesAsync();
}
EditFormVisible = false;
}
public async Task DeleteFlasche(Flasche flasche)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null && flasche != null)
{
_DataContext.Flaschen.Remove(flasche);
await _DataContext.SaveChangesAsync();
}
await ShowFlaschen();
}
}
}

View File

@ -1,4 +1,4 @@
@page "/settings/glaeser"
@page "/settings/glasses"
@using Microsoft.AspNetCore.Components.Sections
<SectionContent SectionId="TopRow.Title">

View File

@ -0,0 +1,127 @@
@page "/settings/ingredients/edit"
@page "/settings/ingredients/edit/{id}"
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Options
@inject IDbContextFactory<DbDataContext> DataContextFactory;
@inject NavigationManager nav;
@inject IWebHostEnvironment env;
@inject IOptions<GeneralSettings> Config;
<SectionContent SectionId="TopRow.Title">
<label>Zutat bearbeiten</label>
</SectionContent>
<div class="d-flex gap-3">
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="name">Name</label>
<input id="cocktailname" name="name" type="text" class="form-control" @bind="@curFlasche.Name" />
</div>
<div class="form-check mb-3">
<InputCheckbox class="form-check-input" id="IsAlcoholic" @bind-Value=@curFlasche.Alkoholisch>Alkoholisch</InputCheckbox>
<label class="form-check-label" for="IsAlcoholic">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-stars text-success" viewBox="0 0 16 16">
<path d="M7.657 6.247c.11-.33.576-.33.686 0l.645 1.937a2.89 2.89 0 0 0 1.829 1.828l1.936.645c.33.11.33.576 0 .686l-1.937.645a2.89 2.89 0 0 0-1.828 1.829l-.645 1.936a.361.361 0 0 1-.686 0l-.645-1.937a2.89 2.89 0 0 0-1.828-1.828l-1.937-.645a.361.361 0 0 1 0-.686l1.937-.645a2.89 2.89 0 0 0 1.828-1.828zM3.794 1.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387A1.73 1.73 0 0 0 4.593 5.69l-.387 1.162a.217.217 0 0 1-.412 0L3.407 5.69A1.73 1.73 0 0 0 2.31 4.593l-1.162-.387a.217.217 0 0 1 0-.412l1.162-.387A1.73 1.73 0 0 0 3.407 2.31zM10.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.16 1.16 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l-.258-.774a1.16 1.16 0 0 0-.732-.732L9.1 2.137a.145.145 0 0 1 0-.274l.774-.258c.346-.115.617-.386.732-.732z" />
</svg>
Alkoholisch
</label>
</div>
<button @onclick="OnSubmit" class="btn btn-primary">Speichern</button>
<button @onclick="@(() => nav.NavigateTo("/settings/ingredients"))" class="btn btn-secondary">Abbrechen</button>
</div>
<div class="border border-2 rounded p-3 w-100">
<div class="mb-3">
<label class="form-label" for="image">Bild</label>
<div class="mb-2">
@if (curFlasche.ImageURL != null)
{
<img style="max-width:128px;" src="@curFlasche.ImageURL" />
}
else
{
<div>Kein Bild vorhanden</div>
}
</div>
<label class="form-label" for="image">Neues Bild hochladen</label>
<InputFile OnChange="Bild_OnChange" class="form-control" id="image" name="image" accept=".jpg,.png,.jpeg,.gif,.webp" />
</div>
</div>
</div>
@code {
[Parameter]
public string? id { get; set; }
public Flasche curFlasche = null!;
public IBrowserFile? NewImage;
private DbDataContext? _DataContext;
protected override async Task OnInitializedAsync()
{
if (id != null)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (_DataContext != null) curFlasche = _DataContext.Flaschen.Single(f => f.Id == Convert.ToInt32(id));
}
// Falls keine ID angegeben wurde oder der Eintrag in der Datenbank nicht gefunden wurde, gehen wir davon aus dass ein neuer Eintrag erstellt wird.
if (curFlasche == null) curFlasche = new();
//await InvokeAsync(StateHasChanged);
}
public void Bild_OnChange(InputFileChangeEventArgs e)
{
NewImage = e.GetMultipleFiles().FirstOrDefault();
//this.StateHasChanged(); War in nem Stackexchange.. Nötig?
}
private async Task OnSubmit(EventArgs e)
{
_DataContext ??= await DataContextFactory.CreateDbContextAsync();
if (curFlasche != null && _DataContext != null)
{
if (id != null)
{
_DataContext.Flaschen.Update(curFlasche);
}
else
{
_DataContext.Flaschen.Add(curFlasche);
}
await _DataContext.SaveChangesAsync();
if (NewImage != null)
{
try
{
// Bild hochladen
var relativeuploadpath = Path.Join(Config.Value.ImageUploadDir, $"ingredient_{curFlasche.Id}{Path.GetExtension(NewImage.Name)}");
var fullpath = Path.Join(env.WebRootPath, relativeuploadpath);
string? folder = Path.GetDirectoryName(fullpath);
if (folder != null && !Path.Exists(folder)) Directory.CreateDirectory(folder);
Stream stream = NewImage.OpenReadStream(maxAllowedSize: Config.Value.MaxAllowedUploadSizeInMB * 1024 * 1024);
FileStream fs = File.Create(fullpath);
await stream.CopyToAsync(fs);
stream.Close();
fs.Close();
curFlasche.ImageURL = relativeuploadpath;
// URL hinterlegen und wieder speichern
_DataContext.Flaschen.Update(curFlasche);
await _DataContext.SaveChangesAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Error uploading image: {ex.Message}");
}
}
}
nav.NavigateTo("/settings/ingredients");
}
}

View File

@ -0,0 +1,140 @@
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.EntityFrameworkCore
@using CocktailWeb.Data
@page "/settings/ingredients"
@inject IDbContextFactory<DbDataContext> FlascheDataContextFactory;
<PageTitle>Zutaten</PageTitle>
<SectionContent SectionId="TopRow.Title">
<label>Einstellungen - Zutaten</label>
</SectionContent>
<a class="btn btn-primary mb-3" href="/settings/ingredients/edit">Neue Zutat</a>
@if (IngredientsList != null && IngredientsList.Count > 0)
{
<div class="table-responsive mt-3">
<table class="table table-striped table-hover table-bordered table-dark border-dark">
<tbody>
@foreach (var fl in IngredientsList)
{
<tr>
<td class="p-0" style="width:64px"><img src="@fl.ImageURL" style="max-width:100%; max-height:auto;" /></td>
<td style="vertical-align:middle;">
@fl.Name
@if (fl.Alkoholisch)
{
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-stars text-success" style="margin-left:15px;" viewBox="0 0 16 16">
<path d="M7.657 6.247c.11-.33.576-.33.686 0l.645 1.937a2.89 2.89 0 0 0 1.829 1.828l1.936.645c.33.11.33.576 0 .686l-1.937.645a2.89 2.89 0 0 0-1.828 1.829l-.645 1.936a.361.361 0 0 1-.686 0l-.645-1.937a2.89 2.89 0 0 0-1.828-1.828l-1.937-.645a.361.361 0 0 1 0-.686l1.937-.645a2.89 2.89 0 0 0 1.828-1.828zM3.794 1.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387A1.73 1.73 0 0 0 4.593 5.69l-.387 1.162a.217.217 0 0 1-.412 0L3.407 5.69A1.73 1.73 0 0 0 2.31 4.593l-1.162-.387a.217.217 0 0 1 0-.412l1.162-.387A1.73 1.73 0 0 0 3.407 2.31zM10.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.16 1.16 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l-.258-.774a1.16 1.16 0 0 0-.732-.732L9.1 2.137a.145.145 0 0 1 0-.274l.774-.258c.346-.115.617-.386.732-.732z" />
</svg>
}
</td>
<td style="text-align:right; vertical-align:middle;">
<a class="btn btn-primary" href="/settings/ingredients/edit/@fl.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDelete(fl)">Löschen</button>
@*
<a class="btn btn-primary" href="/settings/cocktails/edit/@c.Id">Bearbeiten</a>
<button name="submit" type="submit" class="btn btn-outline-danger" @onclick="() => ConfirmDelete(c)">Löschen</button>
*@
</td>
</tr>
}
</tbody>
</table>
</div>
}
<ModalComponent @ref="dlgDelete">
<Title>Löschen bestätigen</Title>
<Body>
Willst du die Zutat wirklich löschen?<br />
Achtung, die Zutat wird auch aus den Maschineneinstellungen entfernt, falls sie dort verwendet worden sein sollte.
</Body>
<Footer>
<button class="btn btn-danger" @onclick="DeleteIngredient">Jo</button>
<button class="btn btn-primary" @onclick="() => CloseDialog(dlgDelete)">Nee</button>
</Footer>
</ModalComponent>
<ModalComponent @ref="dlgInfo">
<Title>Löschen nicht möglich</Title>
<Body>
Die Zutat kann nicht gelöscht werden, da Sie noch in Cocktails verwendet wird:<br />
@InfoText
</Body>
<Footer>
<button class="btn btn-primary" @onclick="() => CloseDialog(dlgInfo)">OK</button>
</Footer>
</ModalComponent>
@code {
public List<Flasche>? IngredientsList { get; set; }
private DbDataContext? _DataContext;
private Flasche? SelectedIngredient;
private ModalComponent dlgDelete = null!;
private ModalComponent dlgInfo = null!;
private string InfoText;
protected override async Task OnInitializedAsync()
{
await FillIngredientsList();
}
public async Task FillIngredientsList()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null)
{
IngredientsList = await _DataContext.Flaschen.OrderBy(f => f.Name).ToListAsync();
}
}
private async Task ConfirmDelete(Flasche fl)
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext == null) throw new Exception("Error creating DataContext");
var CocktailsWithIngredient = _DataContext.Cocktails.Include(c => c.Cocktailflaschen).Where(cf => cf.Cocktailflaschen.Any(cff => cff.Flasche == fl)).OrderBy(c => c.Name).ToList();
if (CocktailsWithIngredient.Count > 0)
{
InfoText = String.Join(", ", CocktailsWithIngredient.Select(c => c.Name).ToArray());
await dlgInfo.OpenModal();
}
else
{
SelectedIngredient = fl;
await dlgDelete.OpenModal();
}
}
public async Task DeleteIngredient()
{
_DataContext ??= await FlascheDataContextFactory.CreateDbContextAsync();
if (_DataContext != null && SelectedIngredient != null)
{
// Zutat aus Maschine rausnehmen (alle Filler, die die Flasche enthalten, auf null setzen)
_DataContext.Fillers.Where(f => f.Flasche == SelectedIngredient)?.ForEachAsync(fil => fil.Flasche = null);
_DataContext.Flaschen.Remove(SelectedIngredient);
await _DataContext.SaveChangesAsync();
await FillIngredientsList();
}
await CloseDialog(dlgDelete);
}
private async Task CloseDialog(ModalComponent dlg)
{
SelectedIngredient = null;
await dlg.Close();
}
}

View File

@ -1,4 +1,4 @@
@page "/settings/maschine";
@page "/settings/machine";
@using Microsoft.EntityFrameworkCore
@using CocktailWeb.Data
@using Microsoft.AspNetCore.Components.Sections

View File

@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Components.Web;
using Microsoft.EntityFrameworkCore;
namespace CocktailWeb.Pages.Settings
{
partial class Maschine
partial class Machine
{
private DbDataContext? _DataContext;
private List<Filler> Fillers { get; set; } = new();

View File

@ -1,4 +1,7 @@
@using Microsoft.AspNetCore.Components.Sections
@using Microsoft.Extensions.Options
@inject IOptions<GeneralSettings> Config
@inject NavigationManager navman
<div class="d-flex align-items-center fixed-top justify-content-between px-4 bg-dark border-primary-subtle" style="border-bottom: 1px solid #d6d5d5; height: 56px; align-items: center; top: 0; z-index: 1;">
<div class="d-flex gap-3 align-items-center">
@ -10,24 +13,107 @@
<SectionOutlet SectionId="Title" />
</div>
<div class="dropdown show">
<a class="btn btn-secondary dropdown-toggle" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-gear-fill" viewBox="0 0 16 16">
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z" />
</svg>
Einstellungen
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="/settings/maschine">Maschine</a>
<a class="dropdown-item" href="/settings/flaschen">Zutaten</a>
<a class="dropdown-item" href="/settings/cocktails">Cocktails</a>
<a class="dropdown-item" href="/settings/glaeser">Gläser</a>
<a class="dropdown-item" href="/serialtest">Serial Test</a>
</div>
<div>
@Environment.MachineName:@navman.ToAbsoluteUri(navman.BaseUri).Port
</div>
@* Einstellungen-Dropdown Menü*@
@if (SettingsUnlocked || Config.Value.SettingsPassword == "" || Config.Value.SettingsPassword == null)
{
<div class="dropdown show z-2">
<a class="btn btn-secondary dropdown-toggle z-2" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-gear-fill" viewBox="0 0 16 16">
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z" />
</svg>
Einstellungen
</a>
<div class="dropdown-menu dropdown-menu-end z-2" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item z-3 position-relative" href="/settings/machine">Maschine</a>
<a class="dropdown-item z-3 position-relative" href="/settings/ingredients">Zutaten</a>
<a class="dropdown-item z-3 position-relative" href="/settings/cocktails">Cocktails</a>
<a class="dropdown-item z-3 position-relative" href="/settings/glasses">Gläser</a>
<a class="dropdown-item z-3 position-relative" href="/serialtest">Serial Test</a>
@if (Config.Value.SettingsPassword != "" && Config.Value.SettingsPassword != null)
{
<a class="dropdown-item z-3 position-relative" @onclick=LockSettings>Einstellungen sperren</a>
}
</div>
</div>
}
else
{
<div class="d-flex gap-3 align-items-center">
<a class="btn btn-secondary" @onclick=OpenDialog>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-lock" viewBox="0 0 16 16">
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2m3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2M5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1" />
</svg>
Einstellungen
</a>
</div>
}
</div>
<ModalComponent @ref="Pwd_Dialog">
<Title>Passwort eingeben</Title>
<Body>
<label class="form-label" for="settingspassword">Passwort</label>
<input class="form-control" id="settingspassword" name="settingspassword" type="text" @bind=@Pwd_inputPassword />
<label class="text-danger">@Pwd_ErrorText</label>
</Body>
<Footer>
<button type="button" class="btn btn-secondary" @onclick="PasswordDialog_Cancel">Abbrechen</button>
<button type="button" class="btn btn-primary" @onclick="PasswordDialog_OK">OK</button>
</Footer>
</ModalComponent>
@code {
public static SectionOutlet Title = new();
public bool SettingsUnlocked;
ModalComponent Pwd_Dialog = null!;
public string? Pwd_inputPassword;
public string? Pwd_ErrorText;
private async Task PasswordDialog_OK(MouseEventArgs e)
{
if (Pwd_inputPassword == Config.Value.SettingsPassword)
{
SettingsUnlocked = true;
await CloseDialog();
}
else
{
Pwd_inputPassword = null;
Pwd_ErrorText = "Falsches Passwort";
}
}
private void LockSettings()
{
SettingsUnlocked = false;
}
private async Task PasswordDialog_Cancel(MouseEventArgs e)
{
await CloseDialog();
}
private async Task OpenDialog()
{
await Pwd_Dialog.OpenModal();
}
private async Task CloseDialog()
{
Pwd_ErrorText = null;
Pwd_inputPassword = null;
await Pwd_Dialog.Close();
}
}

View File

@ -13,6 +13,7 @@
"MaxAllowedUploadSizeInMB": 10,
"ImageUploadDir": "images",
"SerialPort": "COM5",
"Baudrate": 115200
"Baudrate": 115200,
"SettingsPassword": ""
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB