Dev branch
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Elias Jansson
2025-05-31 22:44:15 +02:00
parent eed1ce166f
commit 801e21842a
7 changed files with 892 additions and 3 deletions

View File

@@ -2,6 +2,9 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Aberwyn.Models;
using Aberwyn.Data;
using Microsoft.EntityFrameworkCore;
namespace Aberwyn.Controllers
{
@@ -10,13 +13,20 @@ namespace Aberwyn.Controllers
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
private readonly ApplicationDbContext _context;
public AdminController(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
public AdminController(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
ApplicationDbContext context)
{
_userManager = userManager;
_roleManager = roleManager;
_context = context;
}
public async Task<IActionResult> Index()
{
var users = _userManager.Users.ToList();
@@ -86,8 +96,48 @@ namespace Aberwyn.Controllers
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Todo()
{
return View();
}
[HttpGet]
public async Task<IActionResult> GetTodoTasks()
{
var tasks = await _context.TodoTasks.ToListAsync();
return Json(tasks);
}
[HttpPost]
public async Task<IActionResult> AddTodoTask([FromBody] TodoTask task)
{
task.CreatedAt = DateTime.UtcNow;
task.Priority = task.Priority == 0 ? 1 : task.Priority; // default till låg om ej satt
_context.TodoTasks.Add(task);
await _context.SaveChangesAsync();
return Ok(task);
}
[HttpPost]
public async Task<IActionResult> UpdateTodoTask([FromBody] TodoTask task)
{
var existing = await _context.TodoTasks.FindAsync(task.Id);
if (existing == null) return NotFound();
existing.Title = task.Title;
existing.Status = task.Status;
existing.Priority = task.Priority;
await _context.SaveChangesAsync();
return Ok();
}
}
public class AdminUserViewModel
{
public string UserId { get; set; }

View File

@@ -19,6 +19,7 @@ namespace Aberwyn.Data
public DbSet<AppSetting> AppSettings { get; set; }
public DbSet<BudgetItemDefinition> BudgetItemDefinitions { get; set; }
public DbSet<BudgetCategoryDefinition> BudgetCategoryDefinitions { get; set; }
public DbSet<TodoTask> TodoTasks { get; set; }
}

View File

@@ -0,0 +1,541 @@
// <auto-generated />
using System;
using Aberwyn.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Aberwyn.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20250529183339_CreateTodoTaskTable")]
partial class CreateTodoTaskTable
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.36")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Aberwyn.Models.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("tinyint(1)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetime(6)");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Aberwyn.Models.AppSetting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("AppSettings");
});
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("BudgetCategoryDefinitionId")
.HasColumnType("int");
b.Property<int>("BudgetPeriodId")
.HasColumnType("int");
b.Property<string>("Color")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Order")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("BudgetCategoryDefinitionId");
b.HasIndex("BudgetPeriodId");
b.ToTable("BudgetCategories");
});
modelBuilder.Entity("Aberwyn.Models.BudgetCategoryDefinition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Color")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("BudgetCategoryDefinitions");
});
modelBuilder.Entity("Aberwyn.Models.BudgetItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<decimal>("Amount")
.HasColumnType("decimal(65,30)");
b.Property<int>("BudgetCategoryId")
.HasColumnType("int");
b.Property<int?>("BudgetItemDefinitionId")
.HasColumnType("int");
b.Property<bool>("IncludeInSummary")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsExpense")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Order")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("BudgetCategoryId");
b.HasIndex("BudgetItemDefinitionId");
b.ToTable("BudgetItems");
});
modelBuilder.Entity("Aberwyn.Models.BudgetItemDefinition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("DefaultCategory")
.HasColumnType("longtext");
b.Property<bool>("IncludeInSummary")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsExpense")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("BudgetItemDefinitions");
});
modelBuilder.Entity("Aberwyn.Models.BudgetPeriod", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("Month")
.HasColumnType("int");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<int>("Year")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("BudgetPeriods");
});
modelBuilder.Entity("Aberwyn.Models.PizzaOrder", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("CustomerName")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("IngredientsJson")
.HasColumnType("longtext");
b.Property<DateTime>("OrderedAt")
.HasColumnType("datetime(6)");
b.Property<string>("PizzaName")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Status")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("PizzaOrders");
});
modelBuilder.Entity("Aberwyn.Models.PushSubscriber", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Auth")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Endpoint")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("P256DH")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("PushSubscribers");
});
modelBuilder.Entity("Aberwyn.Models.TodoTask", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("Priority")
.HasColumnType("int");
b.Property<string>("Status")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("TodoTasks");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderKey")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasColumnType("varchar(255)");
b.Property<string>("Name")
.HasColumnType("varchar(255)");
b.Property<string>("Value")
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
{
b.HasOne("Aberwyn.Models.BudgetCategoryDefinition", "Definition")
.WithMany()
.HasForeignKey("BudgetCategoryDefinitionId");
b.HasOne("Aberwyn.Models.BudgetPeriod", "BudgetPeriod")
.WithMany("Categories")
.HasForeignKey("BudgetPeriodId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("BudgetPeriod");
b.Navigation("Definition");
});
modelBuilder.Entity("Aberwyn.Models.BudgetItem", b =>
{
b.HasOne("Aberwyn.Models.BudgetCategory", "BudgetCategory")
.WithMany("Items")
.HasForeignKey("BudgetCategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Aberwyn.Models.BudgetItemDefinition", "BudgetItemDefinition")
.WithMany()
.HasForeignKey("BudgetItemDefinitionId");
b.Navigation("BudgetCategory");
b.Navigation("BudgetItemDefinition");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Aberwyn.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Aberwyn.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Aberwyn.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Aberwyn.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("Aberwyn.Models.BudgetPeriod", b =>
{
b.Navigation("Categories");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Aberwyn.Migrations
{
public partial class CreateTodoTaskTable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "TodoTasks",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Title = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Status = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Priority = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TodoTasks", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "TodoTasks");
}
}
}

View File

@@ -286,6 +286,31 @@ namespace Aberwyn.Migrations
b.ToTable("PushSubscribers");
});
modelBuilder.Entity("Aberwyn.Models.TodoTask", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("Priority")
.HasColumnType("int");
b.Property<string>("Status")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("TodoTasks");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
@@ -416,7 +441,7 @@ namespace Aberwyn.Migrations
modelBuilder.Entity("Aberwyn.Models.BudgetCategory", b =>
{
b.HasOne("Aberwyn.Models.BudgetCategoryDefinition", "BudgetItemDefinition")
b.HasOne("Aberwyn.Models.BudgetCategoryDefinition", "Definition")
.WithMany()
.HasForeignKey("BudgetCategoryDefinitionId");
@@ -428,7 +453,7 @@ namespace Aberwyn.Migrations
b.Navigation("BudgetPeriod");
b.Navigation("BudgetItemDefinition");
b.Navigation("Definition");
});
modelBuilder.Entity("Aberwyn.Models.BudgetItem", b =>

View File

@@ -7,4 +7,14 @@
public string Value { get; set; }
}
public class TodoTask
{
public int Id { get; set; }
public string Title { get; set; }
public string Status { get; set; } // "ideas", "doing", "done"
public DateTime CreatedAt { get; set; }
public int Priority { get; set; }
}
}

View File

@@ -0,0 +1,223 @@
@{
ViewData["Title"] = "Todo";
}
<!DOCTYPE html>
<html lang="sv" ng-app="todoApp">
<head>
<meta charset="utf-8" />
<title>@ViewData["Title"]</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<style>
.todo-board {
padding: 20px;
font-family: sans-serif;
}
.todo-columns {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.todo-column {
background: #f1f5f9;
border-radius: 8px;
padding: 10px;
width: 250px;
min-height: 200px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.todo-column h2 {
margin-top: 0;
}
.todo-task {
background: white;
padding: 8px;
border-radius: 6px;
margin-bottom: 6px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
cursor: move;
}
input[type="text"] {
width: 100%;
margin-top: 8px;
padding: 6px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
margin-top: 6px;
padding: 6px 10px;
background-color: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.priority-low {
border-left: 4px solid #10b981;
}
.priority-medium {
border-left: 4px solid #f59e0b;
}
.priority-high {
border-left: 4px solid #ef4444;
}
</style>
</head>
<body ng-controller="TodoController" class="todo-board" ng-init="loadTasks()">
<h1>🗂️ Min idé-board</h1>
<div class="todo-columns">
<div class="todo-column" ng-repeat="col in columns">
<h2>{{ col.title }}</h2>
<div class="todo-task {{ priorityClass(task.priority) }}"
ng-repeat="task in filteredTasks(col.id) track by task.id"
draggable-task
task="task"
on-task-drop="moveTask(task, col.id)">
{{ task.title }}
<div>
<small>Prioritet:
<select ng-model="task.priority" ng-change="updatePriority(task)">
<option value="1">Låg</option>
<option value="2">Medel</option>
<option value="3">Hög</option>
</select>
</small>
</div>
</div>
<div ng-if="col.id === 'ideas'">
<input type="text" ng-model="newTask.title" placeholder="Ny idé..." />
<select ng-model="newTask.priority">
<option value="1">Låg</option>
<option value="2">Medel</option>
<option value="3">Hög</option>
</select>
<button type="button" ng-click="addTask()">Lägg till</button>
</div>
</div>
</div>
<script>
var app = angular.module("todoApp", []);
app.controller("TodoController", function ($scope, $http) {
$scope.columns = [
{ id: "ideas", title: "💡 Idéer" },
{ id: "doing", title: "🔧 Pågående" },
{ id: "done", title: "✅ Klart" }
];
$scope.tasks = [];
$scope.newTask = {
title: '',
priority: 2
};
$scope.loadTasks = function () {
$http.get("/Admin/GetTodoTasks").then(res => {
$scope.tasks = res.data;
});
};
$scope.addTask = function () {
console.log("addTask:");
const title = $scope.newTask.title;
const priority = $scope.newTask.priority;
if (typeof title !== 'string' || !title.trim()) {
console.warn("Titel är tom eller ogiltig:", title);
return;
}
console.log("post check");
const task = {
title: title.trim(),
status: "ideas",
priority: priority
};
console.log("post title trim");
$http.post("/Admin/AddTodoTask", task, {
headers: { 'Content-Type': 'application/json' }
}).then(res => {
$scope.tasks.push(res.data);
$scope.newTask.title = '';
$scope.newTask.priority = 2;
console.log("Created task");
}, err => {
console.error("Fel vid POST:", err);
});
};
$scope.moveTask = function (task, newStatus) {
task.status = newStatus;
$http.post("/Admin/UpdateTodoTask", task);
};
$scope.updatePriority = function (task) {
$http.post("/Admin/UpdateTodoTask", task);
};
$scope.priorityClass = function (priority) {
return {
1: 'priority-low',
2: 'priority-medium',
3: 'priority-high'
}[priority];
};
$scope.filteredTasks = function (status) {
if (!$scope.tasks || !$scope.tasks.length) return [];
// För säkerhets skull jämför lowercase
return $scope.tasks.filter(t => (t.status || '').toLowerCase() === status.toLowerCase());
};
$scope.loadTasks();
});
app.directive("draggableTask", function () {
return {
restrict: "A",
scope: {
task: "=",
onTaskDrop: "&"
},
link: function (scope, element) {
element.attr("draggable", true);
element.on("dragstart", function (e) {
e.dataTransfer.setData("text/plain", JSON.stringify(scope.task));
});
}
};
});
app.directive("ngRepeat", function () {
return {
restrict: "A",
link: function (scope, element) {
element.on("dragover", function (e) {
e.preventDefault();
element.css("background-color", "#e0f2fe");
});
element.on("dragleave", function () {
element.css("background-color", "");
});
element.on("drop", function (e) {
e.preventDefault();
const data = e.dataTransfer.getData("text/plain");
const task = JSON.parse(data);
scope.onTaskDrop({ task });
element.css("background-color", "");
scope.$apply();
});
}
};
});
</script>
</body>
</html>