示例#1
0
文件: JobPage.cs 项目: TabNoc/PiWeb
        private static void CreateJobAction(JobEntry job, int durationOverride)
        {
            PageStorage <ManualActionExecutionData> .Instance.StorageData.Name          = job.Name;
            PageStorage <ManualActionExecutionData> .Instance.StorageData.ExecutionList = new List <ManualActionExecutionData.ManualActionExecution>();
            foreach (BatchEntry jobBatchEntry in job.BatchEntries)
            {
                PageStorage <ManualActionExecutionData> .Instance.StorageData.ExecutionList.Add(
                    new ManualActionExecutionData.ManualActionExecution(jobBatchEntry.ChannelId, jobBatchEntry.Duration,
                                                                        jobBatchEntry.ActivateMasterChannel, durationOverride));
            }
            PageStorage <ManualActionExecutionData> .Instance.Save();

            PageStorage <ManualActionExecutionData> .Instance.StorageData.Name          = "";
            PageStorage <ManualActionExecutionData> .Instance.StorageData.ExecutionList = null;
        }
示例#2
0
 public static void TimerTick(Object obj)
 {
     try
     {
         JobEntry je = (JobEntry)obj;
         if (je.ListView != null)
         {
             if (je._net != null && je.stat == Status.running)
             {
                 je._net.GetStatus();
             }
             je.ListView.Invoke(je.timerTickCallback, new Object[] { obj });
         }
     }
     catch { }
 }
示例#3
0
        /// <summary>
        /// Creates the new job.
        /// </summary>
        /// <param name="jobDefinition">The job definition.</param>
        /// <returns></returns>
        public Guid CreateNewJob(IJobDefinitionCreate jobDefinition)
        {
            var jobEntity = new JobEntry
            {
                Description             = jobDefinition.Description,
                FailIfAnyTaskHasError   = jobDefinition.FailIfAnyTaskHasError,
                FailIfAnyTaskHasWarning = jobDefinition.FailIfAnyTaskHasWarning,
                IsEnabled = true,
                Name      = jobDefinition.Name,
                Position  = engineRepository.GetJobs().Select(j => j.Position).DefaultIfEmpty().Max() + 1
            };

            using (var transaction = uow.BeginTransaction())
            {
                engineRepository.CreateJob(jobEntity);
            }

            return(jobEntity.Id);
        }
示例#4
0
        public Task <Guid> StartJob(IWorkContext context, IJob job, Action <IWorkContext, IJobResult> completionNotification)
        {
            job.Verify(nameof(job)).IsNotNull();
            completionNotification.Verify(nameof(completionNotification)).IsNotNull();

            lock (_lock)
            {
                var jobEntry = new JobEntry(job, completionNotification);

                _currentJob.Add(jobEntry.JobId, jobEntry);

                context.Telemetry.Verbose(context, $"Starting Job Id={jobEntry.JobId}");

                jobEntry.RunningTask = Task.Run(async() => await job.Start(context))
                                       .ContinueWith(x => Completed(context, x, jobEntry.JobId, job.GetResult(context)));

                context.Telemetry.Verbose(context, $"Started Job Id={jobEntry.JobId}");
                return(Task.FromResult(jobEntry.JobId));
            }
        }
示例#5
0
        public async Task <bool> StopJob(IWorkContext context, Guid jobId)
        {
            JobEntry jobEntry = null;

            lock (_lock)
            {
                if (!_currentJob.TryGetValue(jobId, out jobEntry))
                {
                    return(false);
                }

                Verify.Assert <InvalidOperationException>(_currentJob.Remove(jobId), $"Failed to remove job id {jobId} from collection");
            }

            if (jobEntry.RunningTask.IsCompleted)
            {
                await jobEntry.Job.Stop(context);
            }

            return(true);
        }
示例#6
0
    public static void InvokedTimerTick(Object obj)
    {
        JobEntry je = (JobEntry)obj;

        try
        {
            if (je._job != null)
            {
                int id = je._job.Id; //Test if the process exists.
                je._job.Refresh();
                if (!je._job.HasExited)
                {
                    System.TimeSpan diff1 = DateTime.Now.Subtract(je._job.StartTime);
                    //je.SubItems[(int)Display.cpu].Text = diff1.TotalSeconds.ToString("#0.0")+"s";
                    je.SubItems[(int)Display.cpu].Text = je._job.TotalProcessorTime.TotalSeconds.ToString("#0.0") + "s";
                    je.SubItems[(int)Display.mem].Text = (1 + je._job.WorkingSet64 / 1024).ToString("n0") + "kb";
                }
            }
            else if (je._net != null)
            {
                je.SetCpuAndMem();
            }
        }
        catch //This might be a _net job
        {
            if (je._net != null)
            {
            }
        }

        if (je.stat == Status.scheduled && DateTime.Compare(DateTime.Now, je._schedTime) > 0)
        {
            je.SetStatus(Status.queued);
        }
        else if (je.stat == Status.rscheduled && DateTime.Compare(DateTime.Now, je._schedTime) > 0)
        {
            je.SetStatus(Status.rqueued);
        }
    }
示例#7
0
        private void Completed(IWorkContext context, Task task, Guid jobId, IJobResult jobResult)
        {
            JobEntry jobEntry = null;

            lock (_lock)
            {
                if (!_currentJob.TryGetValue(jobId, out jobEntry))
                {
                    return;
                }

                context.Telemetry.Verbose(context, $"Removed {jobId} from current job list because signaled completed");
                _currentJob.Remove(jobId);
            }

            JobStatus status = task.IsFaulted ? JobStatus.Faulted : jobResult.Status;

            TimeSpan duration = DateTimeOffset.Now - jobEntry.StartTime;
            string   msg      = $"Job completed - Job Id={jobId}, Status={jobResult.Status}, IsFaulted={task.IsFaulted}, Duration={duration}";

            if (!task.IsFaulted && jobResult.Status == JobStatus.Completed)
            {
                context.Telemetry.Verbose(context, msg);
            }
            else
            {
                context.Telemetry.Error(context, msg, task.Exception);
            }

            jobEntry?.CompletionNotification(context, new JobResult(jobId, status, duration, jobResult.Errors, task.Exception));

            if (task.IsFaulted)
            {
                context.Telemetry.Verbose(context, "Task disposed");
                task.Dispose();
            }
        }
示例#8
0
文件: JobPage.cs 项目: TabNoc/PiWeb
        public JobPage(JobEntry job, ManualPage parent) : base("div")
        {
            this._job = job;
            SetBorder(BorderKind.Rounded, StylingColor.Secondary);

            #region Initialize Grid

            Grid grid = new Grid(this);
            grid.AddStyling(StylingOption.MarginRight, 2);
            grid.AddStyling(StylingOption.MarginLeft, 2);
            grid.AddStyling(StylingOption.MarginTop, 4);
            grid.AddStyling(StylingOption.MarginBottom, 2);

            #endregion Initialize Grid

            #region JobName

            MultiInputGroup jobNameMultiInputGroup = new MultiInputGroup();
            jobNameMultiInputGroup.AppendLabel("JobName");
            StylableTextInput jobNameTextInput = jobNameMultiInputGroup.AppendTextInput("Name?", startText: job.Name);
            jobNameMultiInputGroup.AppendValidation("", "Ein Job mit diesem Namen existiert bereits", false);
            Button saveJobNameButton = jobNameMultiInputGroup.AppendCustomElement(new Button(StylingColor.Success, asOutline: true, text: "Namen übernehmen", fontAwesomeIcon: "save"), false);
            Button deleteJobButton   = jobNameMultiInputGroup.AppendCustomElement(new Button(StylingColor.Danger, asOutline: true, text: "Job Löschen", fontAwesomeIcon: "trash"), false);
            deleteJobButton.Click += (sender, args) =>
            {
                const string confirmMessage = "Wirklich Löschen";
                if (deleteJobButton.Text != confirmMessage)
                {
                    deleteJobButton.Text = confirmMessage;
                    return;
                }
                else
                {
                    PageStorage <ManualData> .Instance.StorageData.JobEntries.Remove(job);

                    parent.UpdateJobs();
                }
            };

            saveJobNameButton.Click += (sender, args) =>
            {
                if (PageStorage <ManualData> .Instance.StorageData.JobEntries.Any(entry => entry.Name == jobNameTextInput.Value))
                {
                    if (job.Name == jobNameTextInput.Value)
                    {
                        return;
                    }
                    else
                    {
                        jobNameTextInput.SetValidation(false, true);
                    }
                }
                else
                {
                    jobNameTextInput.SetValidation(true, false);
                    job.Name = jobNameTextInput.Value;
                    parent.UpdateJobs();
                }
            };
            grid.AddRow().AppendCollum(jobNameMultiInputGroup, autoSize: true);

            #endregion JobName

            #region ExecuteJob

            #region Init Container

            Container firstContainer = new Container();
            firstContainer.SetBorder(BorderKind.Rounded, StylingColor.Info);
            firstContainer.AddStyling(StylingOption.MarginTop, 3);
            firstContainer.AddStyling(StylingOption.MarginBottom, 1);
            firstContainer.AddStyling(StylingOption.PaddingTop, 3);
            firstContainer.AddStyling(StylingOption.PaddingBottom, 2);
            grid.AddRow().AppendCollum(firstContainer, autoSize: true);

            #endregion Init Container

            #region create Heading

            Heading firstHeading = new Heading(5, "Job Ausführen ...");
            firstContainer.AppendChild(firstHeading);

            #endregion create Heading

            #region Override

            OverrideInputGroup overrideInputGroup = new OverrideInputGroup(100);
            firstContainer.AppendChild(overrideInputGroup);

            #endregion Override

            #region StartButton

            Button startButton = new Button(StylingColor.Success, true, text: "Einreihen!", fontAwesomeIcon: "plus-circle", asBlock: true);
            firstContainer.AppendChild(startButton);
            startButton.Click += (o, args) =>
            {
                startButton.IsDisabled = true;
                try
                {
                    CreateJobAction(job, overrideInputGroup.Value);

                    startButton.Text = "Wurde Eingereiht";
                    Task.Run(() =>
                    {
                        System.Threading.Thread.Sleep(5000);
                        startButton.Text = "Einreihen!";
                        startButton.SetFontAwesomeIcon("plus-circle");
                        return(startButton.IsDisabled = false);
                    });
                }
                catch (Exception)
                {
                    startButton.Text = "Einreihen fehlgeschlagen";
                    throw;
                }
            };
            firstContainer.AppendChild(startButton);
            startButton.AddStyling(StylingOption.MarginBottom, 2);

            #endregion StartButton

            #endregion ExecuteJob

            grid.AddRow().AppendCollum(new Heading(4, "Batch Einträge"), autoSize: true);
            List batchEntries = grid.AddRow().AppendCollum(new List(false), autoSize: true);
            foreach (BatchEntry jobBatchEntry in job.BatchEntries)
            {
                batchEntries.AppendChild(new ListItem()
                {
                    Text = $"{jobBatchEntry.Name} {jobBatchEntry.ToString()}"
                });
            }
        }
示例#9
0
        static void Main(string[] args)
        {
            ShowIntro();

            random = new Random();

            BootloaderJobsLoader btp = new BootloaderJobsLoader();

            Console.WriteLine($"Reading task file...");
            try
            {
                btp.LoadTasks("bootloader_tasks_real.json");
            }
            catch (Exception ex)
            {
                ColorConsole.WriteLine(ConsoleColor.Red, "Error druing reading: " + ex.Message);
            }


            // Find highest bootloader id
            byte[] addresses_to_check = btp.Jobs.Where(x => x.BootloaderID.HasValue).Select(x => x.BootloaderID.Value).Distinct().ToArray();

            // Show some summary
            Console.WriteLine($"Task summary:");
            Console.WriteLine($"   Found {btp.Count} task(s).");
            Console.WriteLine($"   Highest bootloader ID: 0x{addresses_to_check.Max():X2}");
            Console.WriteLine($"   Unique bootloaders (by ID): {btp.Jobs.Select(x => x.BootloaderID).Where(x => x.HasValue).Distinct().Count()}");
            Console.WriteLine($"   Unique bootloaders: {string.Join(",", addresses_to_check.Select(x => "0x" + x.ToString("X2")).Distinct())}");

            //
            // Wait for all serial ports to be connected and identified
            AVRBootloaderCnC cnc = new AVRBootloaderCnC();

            cnc.SendAdvertisementToEveryDetectedPort();

            // Scan all available serial ports for bootloaders
            cnc.AcquireBootloaderDevicesInParallel(addresses_to_check);



            // show found devices
            cnc.ShowDevices();


            for (int job_index = 0; job_index < btp.Count; job_index++)
            {
                JobEntry          job_entry           = btp.Jobs[job_index];
                JobTypeDescriptor job_type_descriptor = JobTypeDescriptorCollection.GetDescriptor(job_entry.JobType);
                ColorConsole.WriteLine(ConsoleColor.Cyan, $"Running task {job_index}: {job_entry.JobType} for device {job_entry.CPU} ID={job_entry.BootloaderID:X2}...");

                // Get the device
                BootloaderClient device = cnc.Devices.Where(x => x.BootloaderAddress == job_entry.BootloaderID).FirstOrDefault();
                if (device == null && job_type_descriptor.IsPhysicalDeviceNeeded)
                {
                    ColorConsole.WriteLine(ConsoleColor.Yellow, "   No proper device found.");
                    continue;
                }

                if (job_entry.JobType == JobType.ReadEepromMemory)
                {
                    MemoryMap mm = new MemoryMap(job_entry.ProgrammableMemorySize);

                    cnc.ReadEEPROM(device, mm);
                    IntelHEX16Storage storage = new IntelHEX16Storage(mm);
                    storage.Save(job_entry.FileName);
                }

                if (job_entry.JobType == JobType.ReadFlashMemory)
                {
                    MemoryMap mm = new MemoryMap(job_entry.ProgrammableMemorySize);
                    cnc.ReadFLASH(device, mm);
                    IntelHEX16Storage storage = new IntelHEX16Storage(mm);
                    storage.Save(job_entry.FileName);
                }

                if (job_entry.JobType == JobType.WriteEepromMemory)
                {
                    FileInfo          fi      = new FileInfo(job_entry.FileName);
                    MemoryMap         mm      = new MemoryMap(job_entry.ProgrammableMemorySize);
                    IntelHEX16Storage storage = new IntelHEX16Storage(mm);
                    storage.Load(fi.FullName);
                    Console.WriteLine($"   File name: {fi.FullName}");
                    Console.WriteLine($"   Modified.: {fi.LastWriteTime}");
                    cnc.WriteEEPROM(device, mm);
                }


                if (job_entry.JobType == JobType.WriteFlashMemory)
                {
                    FileInfo          fi      = new FileInfo(job_entry.FileName);
                    MemoryMap         mm      = new MemoryMap(job_entry.ProgrammableMemorySize);
                    IntelHEX16Storage storage = new IntelHEX16Storage(mm);
                    storage.Load(fi.FullName);
                    Console.WriteLine($"   File name: {fi.FullName}");
                    Console.WriteLine($"   Modified.: {fi.LastWriteTime}");
                    cnc.WriteFLASH(device, mm);
                }

                if (job_entry.JobType == JobType.Reboot)
                {
                    cnc.Reboot(device);
                }

                if (job_entry.JobType == JobType.WaitForKey)
                {
                    if (!string.IsNullOrEmpty(job_entry.WaitForKeyMessage))
                    {
                        ColorConsole.PressAnyKey(job_entry.WaitForKeyMessage);
                    }
                    else
                    {
                        ColorConsole.PressAnyKey();
                    }
                }

                if (job_entry.JobType == JobType.ReadBootloaderVersion)
                {
                    string ver = "";
                    cnc.ReadBootloaderVersion(device, ref ver);
                }
            }

            ColorConsole.PressAnyKey();
        }
示例#10
0
    public void Run(FileType what, string fname, JobEntry je, ref string errortext)
    {
        string image;

        lock (io)
        {
            io.locker++;
            switch (what)
            {
            case FileType.sfbox:
                io.WriteLine("RUN " + fname);
                break;

            case FileType.mcrenko:
                io.WriteLine("RUNMC " + fname);
                break;

            case FileType.mccompile:
                io.WriteLine("RUNMCCOMPILE " + fname);
                break;

            case FileType.ctb:
                io.WriteLine("RUNCTB " + fname);
                break;
            }
            image = io.ReadLine();
            if (image.Substring(0, 1) == "+")
            {
                //je.timer.Change(500,2000);
                image = io.ReadLine();
                while (true)
                {
                    if (image.Length >= 13 && image.Substring(0, 13) == "+OK  Finished")
                    {
                        break;
                    }
                    else if (image.Length == 12 && image.Substring(0, 12) == "+OK  Stopped")
                    {
                        je.SetStatus(Status.waiting);
                    }
                    else if (image.Length == 14 && image.Substring(0, 14) == "+OK  Continued")
                    {
                        je.SetStatus(Status.resumed);
                    }
                    else
                    {
                        //throw new DivideByZeroException("Invalid Division");
                        try {
                            je._theTabs.BeginInvoke(je.asyncReadCallback, new Object[] { image + "\r\n" });
                        }
                        catch (Exception e) {
                            errortext = e.Message;
                            break;
                        }
                    }
                    image = io.ReadLine();
                }
                //je.timer.Change(0,0);
            }
            else if (image.Length > 5)
            {
                errortext = image.Substring(5);
            }
            else
            {
                errortext = "Unknown error whilst running. \r\nUnknown RUN command?";
            }
        }
    }
示例#11
0
 public SfbClient(JobEntry je)
 {
     this.je = je;
 }
示例#12
0
    static void RunAndDownload(SfbClient _net, string shortName, string directoryName, JobEntry je)
    {
        je.RunAndDownloadIsActive = true;
        string errortext = null;

        _net.Run(je.filetype, shortName, je, ref errortext);

        if (errortext == "Maximum number of concurrent jobs exceeded.")
        {
            _net.Disconnect();
            je.WriteToLog(errortext.ToLower());
            je.SetStatus(Status.schedulerequest);
        }
        else if (errortext != null)
        {
            _net.Disconnect();
            MessageBoxShow(je._houston, errortext, "Run error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            _net.GetFinalStatus();
            je.SetCpuAndMem();

            _net.Download(je.DirectoryName);
            //je.WriteToLog("downloading finished");
            _net.Disconnect();
            if (je.stat == Status.aborted)
            {
                je.WriteToLog("abort completed");
            }
        }
    }
示例#13
0
        public void TaskFlowTest()
        {
            var uow = serviceProvider.GetService <IUnitOfWork>();
            var engineRepository = serviceProvider.GetService <IEngineRepository>();
            var engine           = serviceProvider.GetService <IEngine>();

            engine.Init();

            JobEntry jobEntry = null;

            //Create entities to test
            using (var transaction = uow.BeginTransaction())
            {
                //Job
                jobEntry = GetJobEntry();
                engineRepository.CreateJob(jobEntry);

                //Task
                TaskEntry taskEntry = GetTaskEntry();
                taskEntry.ParentJob = jobEntry;
                engineRepository.CreateTask(taskEntry);

                //Module Common
                var commonModuleEntry = new CommonModuleEntry();
                commonModuleEntry.InputProperties.FirstOrDefault(x => x.Key == "WorkspacePath").Value = new VirtualPathValue(new VirtualPath(@".\")).WriteToStringValue();
                engineRepository.CreateModule(commonModuleEntry);

                //first
                var elementFlatileReaderEntry = GetFlatFileReaderEntry();
                elementFlatileReaderEntry.ParentTask   = taskEntry;
                elementFlatileReaderEntry.Position     = 1;
                elementFlatileReaderEntry.ParentModule = commonModuleEntry;
                engineRepository.CreateElement(elementFlatileReaderEntry);

                //second
                var elementFlatFileWriterEntry = GetFlatFileWriterEntry();
                elementFlatFileWriterEntry.ParentTask   = taskEntry;
                elementFlatFileWriterEntry.Position     = 3;
                elementFlatFileWriterEntry.ParentModule = commonModuleEntry;
                engineRepository.CreateElement(elementFlatFileWriterEntry);

                //link
                var linkElement = new ElementsLinkEntry(elementFlatileReaderEntry, elementFlatFileWriterEntry);
                linkElement.ParentTask = taskEntry;
                linkElement.Mappings.Add(new ElementsMappingEntry
                {
                    InputPropertyKey  = "Table",
                    OutputPropertyKey = "Table",
                    ParentLink        = linkElement
                });
                linkElement.Position = 2;

                engineRepository.CreateElement(linkElement);

                taskEntry.Elements.Add(elementFlatileReaderEntry);
                taskEntry.Elements.Add(linkElement);
                taskEntry.Elements.Add(elementFlatFileWriterEntry);

                jobEntry.Tasks.Add(taskEntry);
            }

            engine.ExecuteJob(jobEntry.Id);
        }
        public void LoadTasks(string taskDescriptionFile)
        {
            // Read tasks
            Jobs.JobEntryCollection collection = null;
            try
            {
                string content = File.ReadAllText(taskDescriptionFile);
                collection = JsonConvert.DeserializeObject <Jobs.JobEntryCollection>(content);
            }
            catch (IOException ioex)
            {
                throw new BootloaderException($"Job list load error: {ioex.Message}", ioex);
            }
            catch (JsonException jex)
            {
                throw new BootloaderException($"Job list parsing error: {jex.Message}", jex);
            }

            // Verify jobs
            for (int i = 0; i < collection.Jobs.Length; i++)
            {
                JobEntry task = collection.Jobs[i];
                try
                {
                    //todo: refactorize
                    if (task.JobType == JobType.WriteEepromMemory)
                    {
                        //TODO: replace fake load into fake memory with a clear verification procedure
                        MemoryMap         mm = new MemoryMap(task.ProgrammableMemorySize);
                        IntelHEX16Storage s  = new IntelHEX16Storage(mm);
                        s.Load(task.FileName);
                    }

                    if (task.JobType == JobType.WriteFlashMemory)
                    {
                        //TODO: replace fake load into fake memory with a clear verification procedure
                        MemoryMap         mm = new MemoryMap(task.ProgrammableMemorySize);
                        IntelHEX16Storage s  = new IntelHEX16Storage(mm);
                        s.Load(task.FileName);
                    }
                    if (task.JobType == JobType.ReadFlashMemory || task.JobType == JobType.ReadEepromMemory)
                    {
                        //TODO: replace fake load into fake memory with a clear verification procedure
                        //  MemoryMap mm = new MemoryMap(task.ProgrammableMemorySize);
                        // IntelHEX16Storage s = new IntelHEX16Storage(mm);
                        //s.Load(task.FileName);
                    }
                    if (task.JobType == JobType.Reboot)
                    {
                        //?
                    }
                }
                catch (Exception ex)
                {
                    throw new BootloaderException($"Job verification failed ({task.JobType}, task #{i}): {ex.Message}", ex);
                }
            }

            // Seems ok
            this.jobs = collection.Jobs;
        }
示例#15
0
文件: BatchPage.cs 项目: TabNoc/PiWeb
        public BatchPage(BatchEntry batch, ManualPage parent) : base("div")
        {
            const int labelSize = 100;

            _batch = batch;
            SetBorder(BorderKind.Rounded, StylingColor.Secondary);

            #region Initialize Grid

            Grid grid = new Grid(this);
            grid.AddStyling(StylingOption.MarginRight, 2);
            grid.AddStyling(StylingOption.MarginLeft, 2);
            grid.AddStyling(StylingOption.MarginTop, 4);
            grid.AddStyling(StylingOption.MarginBottom, 2);

            #endregion Initialize Grid

            #region JobName

            MultiInputGroup batchNameMultiInputGroup = new MultiInputGroup();
            batchNameMultiInputGroup.AppendLabel("BatchName", labelSize);
            StylableTextInput batchNameTextInput = batchNameMultiInputGroup.AppendTextInput("Name?", startText: batch.Name);
            batchNameMultiInputGroup.AppendValidation("", "Ein Batch-Auftrag mit diesem Namen existiert bereits", false);
            batchNameMultiInputGroup.AppendCustomElement(new Button(StylingColor.Success, asOutline: true, text: "Namen übernehmen", fontAwesomeIcon: "save"), false).Click += (sender, args) =>
            {
                if (batchNameTextInput.Value == "")
                {
                    batchNameTextInput.SetValidation(false, true);
                    return;
                }
                if (PageStorage <ManualData> .Instance.StorageData.BatchEntries.Any(entry => entry.Name == batchNameTextInput.Value))
                {
                    if (batch.Name == batchNameTextInput.Value)
                    {
                        return;
                    }
                    else
                    {
                        batchNameTextInput.SetValidation(false, true);
                    }
                }
                else
                {
                    batchNameTextInput.SetValidation(true, false);
                    foreach (BatchEntry entry in PageStorage <ManualData> .Instance.StorageData.JobEntries.SelectMany(
                                 entry => entry.BatchEntries.Where(batchEntry =>
                                                                   batchEntry.Name == batch.Name && batchEntry != batch)))
                    {
                        entry.Name = batchNameTextInput.Value;
                    }
                    batch.Name = batchNameTextInput.Value;
                    parent.UpdateBatch();
                }
            };

            Button deleteJobButton = batchNameMultiInputGroup.AppendCustomElement(new Button(StylingColor.Danger, asOutline: true, text: "Batch-Auftrag Löschen", fontAwesomeIcon: "trash"), false);
            deleteJobButton.Click += (sender, args) =>
            {
                const string confirmMessage = "Wirklich Löschen";
                if (deleteJobButton.Text != confirmMessage)
                {
                    deleteJobButton.Text = confirmMessage;
                    return;
                }
                else
                {
                    PageStorage <ManualData> .Instance.StorageData.BatchEntries.Remove(batch);

                    List <JobEntry> removeList = new List <JobEntry>();

                    foreach (JobEntry entry in PageStorage <ManualData> .Instance.StorageData.JobEntries.Where(entry =>
                                                                                                               entry.BatchEntries.Any(batchEntry => batchEntry.Name == batch.Name)))
                    {
                        entry.BatchEntries.RemoveAll(batchEntry => batchEntry.Name == batch.Name);
                        if (entry.BatchEntries.Count == 0)
                        {
                            removeList.Add(entry);
                        }
                    }

                    foreach (JobEntry jobEntry in removeList)
                    {
                        PageStorage <ManualData> .Instance.StorageData.JobEntries.Remove(jobEntry);
                    }

                    parent.UpdateBatch();
                    parent.UpdateJobs();
                }
            };

            batchNameMultiInputGroup.AddStyling(StylingOption.MarginBottom, 2);
            grid.AddRow().AppendCollum(batchNameMultiInputGroup, autoSize: true);

            MultiInputGroup batchActionMultiInputGroup = new MultiInputGroup();
            batchActionMultiInputGroup.AppendLabel("Aktion", labelSize);
            batchActionMultiInputGroup.AppendLabel(batch.ToString());
            batchActionMultiInputGroup.AddStyling(StylingOption.MarginBottom, 1);
            grid.AddRow().AppendCollum(batchActionMultiInputGroup, autoSize: true);

            #endregion JobName

            #region ExecuteAction

            #region Init Container

            Container firstContainer = new Container();
            firstContainer.SetBorder(BorderKind.Rounded, StylingColor.Info);
            firstContainer.AddStyling(StylingOption.MarginTop, 3);
            firstContainer.AddStyling(StylingOption.MarginBottom, 1);
            firstContainer.AddStyling(StylingOption.PaddingTop, 3);
            firstContainer.AddStyling(StylingOption.PaddingBottom, 2);
            grid.AddRow().AppendCollum(firstContainer, autoSize: true);

            #endregion Init Container

            #region create Heading

            Heading firstHeading = new Heading(5, "Batch Ausführen ...");
            firstContainer.AppendChild(firstHeading);

            #endregion create Heading

            #region Override

            OverrideInputGroup overrideInputGroup = new OverrideInputGroup(100);
            firstContainer.AppendChild(overrideInputGroup);

            #endregion Override

            #region StartButton

            Button startButton = new Button(StylingColor.Success, true, text: "Einreihen!", fontAwesomeIcon: "plus-circle", asBlock: true);
            firstContainer.AppendChild(startButton);
            startButton.Click += (o, args) =>
            {
                startButton.IsDisabled = true;
                try
                {
                    CreateBatchAction(batch, overrideInputGroup.Value);

                    startButton.Text = "Wurde Eingereiht";
                    Task.Run(() =>
                    {
                        System.Threading.Thread.Sleep(5000);
                        startButton.Text = "Einreihen!";
                        startButton.SetFontAwesomeIcon("plus-circle");
                        return(startButton.IsDisabled = false);
                    });
                }
                catch (Exception)
                {
                    startButton.Text = "Einreihen fehlgeschlagen";
                    throw;
                }
            };
            firstContainer.AppendChild(startButton);
            startButton.AddStyling(StylingOption.MarginBottom, 2);

            #endregion StartButton

            #endregion ExecuteAction

            #region AddToJob

            #region Init Container

            Container secondContainer = new Container();
            secondContainer.SetBorder(BorderKind.Rounded, StylingColor.Info);
            secondContainer.AddStyling(StylingOption.MarginTop, 3);
            secondContainer.AddStyling(StylingOption.MarginBottom, 1);
            secondContainer.AddStyling(StylingOption.PaddingTop, 3);
            secondContainer.AddStyling(StylingOption.PaddingBottom, 2);
            grid.AddRow().AppendCollum(secondContainer, autoSize: true);

            #endregion Init Container

            #region create Heading

            Heading heading = new Heading(5, "... zu Job-Auftrag hinzufügen");
            secondContainer.AppendChild(heading);

            #endregion create Heading

            #region JobName Input

            _jobNameMultiInputGroup = new MultiInputGroup();
            _jobNameMultiInputGroup.AddStyling(StylingOption.MarginTop, 4);
            _jobNameMultiInputGroup.AppendLabel("Name für den Job-Auftrag:");
            StylableTextInput jobNameTextInput = _jobNameMultiInputGroup.AppendTextInput("Name?");
            _jobNameMultiInputGroup.AppendValidation("", "Es gibt bereits einen Job mit diesem Namen", false);
            _jobNameMultiInputGroup.IsHidden = true;
            secondContainer.AppendChild(_jobNameMultiInputGroup);

            #endregion JobName Input

            #region jobSelect

            MultiInputGroup jobSelectMultiInputGroup = new MultiInputGroup();
            jobSelectMultiInputGroup.AddStyling(StylingOption.MarginTop, 4);
            jobSelectMultiInputGroup.AppendLabel("Ziel Job:");
            _jobSelectDropdown = jobSelectMultiInputGroup.AppendCustomElement(new Dropdown(new Button(StylingColor.Secondary, true, text: "Bitte Wählen!"), DropdownDirection.DropDown), false);
            FillJobDropDown();
            jobSelectMultiInputGroup.AppendValidation("", "Dieser Batch-Auftrag ist bereits Bestandteil des Jobs", true);
            secondContainer.AppendChild(jobSelectMultiInputGroup);

            #endregion jobSelect

            #region Appent To Job or Create New

            _appendToJobButton = new Button(StylingColor.Success, true, text: "Zu Job-Auftrag hinzufügen", fontAwesomeIcon: "save", asBlock: true);
            _appendToJobButton.AddStyling(StylingOption.MarginTop, 2);
            _appendToJobButton.Click += (sender, args) =>
            {
                if (batchNameTextInput.Value == "")
                {
                    jobNameTextInput.SetValidation(false, true);
                    return;
                }
                if (_jobSelectDropdown.Button.Text == NewJobString)
                {
                    if (PageStorage <ManualData> .Instance.StorageData.JobEntries.Any(entry => entry.Name == jobNameTextInput.Value) || jobNameTextInput.Value == "")
                    {
                        // Invalid entered Name
                        jobNameTextInput.SetValidation(false, true);
                    }
                    else
                    {
                        // Create Job
                        jobNameTextInput.SetValidation(true, false);
                        PageStorage <ManualData> .Instance.StorageData.JobEntries.Add(new JobEntry(jobNameTextInput.Value, batch));

                        parent.UpdateJobs();
                        _jobNameMultiInputGroup.IsHidden = true;
                        _jobSelectDropdown.Button.Text   = jobNameTextInput.Value;

                        _appendToJobButton.IsHidden   = true;
                        _removeFromJobButton.IsHidden = false;
                    }
                }
                else
                {
                    jobNameTextInput.SetValidation(false, false);

                    // Add To Job
                    PageStorage <ManualData> .Instance.StorageData.JobEntries.First(entry => entry.Name == _jobSelectDropdown.Button.Text).BatchEntries.Add(batch);

                    parent.UpdateJobs();

                    _appendToJobButton.IsHidden   = true;
                    _removeFromJobButton.IsHidden = false;
                }
            };
            secondContainer.AppendChild(_appendToJobButton);

            #endregion Appent To Job or Create New

            #region Remove From Job

            _removeFromJobButton = new Button(StylingColor.Danger, true, text: "Aus Job löschen", fontAwesomeIcon: "trash", asBlock: true);
            _removeFromJobButton.AddStyling(StylingOption.MarginTop, 2);
            _removeFromJobButton.IsHidden = true;
            _removeFromJobButton.Click   += (sender, args) =>
            {
                if (PageStorage <ManualData> .Instance.StorageData.JobEntries.Any(entry => entry.Name == _jobSelectDropdown.Button.Text))
                {
                    JobEntry jobEntry = PageStorage <ManualData> .Instance.StorageData.JobEntries.First(entry => entry.Name == _jobSelectDropdown.Button.Text);

                    jobEntry.BatchEntries.RemoveAll(entry => entry.Name == _batch.Name);
                    if (jobEntry.BatchEntries.Count == 0)
                    {
                        PageStorage <ManualData> .Instance.StorageData.JobEntries.Remove(jobEntry);
                    }
                }
                _removeFromJobButton.IsHidden = true;
                _appendToJobButton.IsHidden   = false;
                FillJobDropDown();
                parent.UpdateJobs();
            };
            secondContainer.AppendChild(_removeFromJobButton);

            #endregion Remove From Job

            #endregion AddToJob
        }