Merge branch 'feature/api_enhancements' into develop
This commit is contained in:
commit
862ef9fe88
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@ -15,9 +15,9 @@
|
||||
"SECRET_KEY" : "zdiTz8P3jXOc7jztIQAoelK4zztyuCpJ" // https://randomkeygen.com/
|
||||
},
|
||||
"args": [
|
||||
"run" //,
|
||||
// "--no-debugger",
|
||||
//"--no-reload"
|
||||
"run",
|
||||
// "--no-debugger",
|
||||
"--no-reload"
|
||||
],
|
||||
"jinja": true,
|
||||
"justMyCode": true
|
||||
|
||||
5890
misc/BreCalApi.cs
5890
misc/BreCalApi.cs
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
87
misc/update_1.1_to_1.2.sql
Normal file
87
misc/update_1.1_to_1.2.sql
Normal file
@ -0,0 +1,87 @@
|
||||
-- add notification handling columns to shipcall
|
||||
-- evaluation_time: Time when the "traffic light" was last changed
|
||||
-- evaluation_notifications_sent: Flag to indicate if notifications were sent for the current evaluation
|
||||
|
||||
ALTER TABLE `bremen_calling_devel`.`shipcall`
|
||||
ADD COLUMN `evaluation_time` DATETIME NULL DEFAULT NULL AFTER `evaluation_message`,
|
||||
ADD COLUMN `evaluation_notifications_sent` BIT NULL AFTER `evaluation_time`;
|
||||
|
||||
|
||||
|
||||
-- prepare notification table for historic notification data
|
||||
-- removed reference to participant and times and dropped unnecessary columns
|
||||
-- added reference to shipcall
|
||||
|
||||
ALTER TABLE `bremen_calling_devel`.`notification`
|
||||
DROP FOREIGN KEY `FK_NOT_TIMES`,
|
||||
DROP FOREIGN KEY `FK_NOT_PART`;
|
||||
ALTER TABLE `bremen_calling_devel`.`notification`
|
||||
DROP COLUMN `deleted`,
|
||||
DROP COLUMN `acknowledged`,
|
||||
DROP COLUMN `participant_id`,
|
||||
DROP COLUMN `times_id`,
|
||||
ADD COLUMN `shipcall_id` INT UNSIGNED NULL AFTER `id`,
|
||||
ADD INDEX `FK_NOTIFICATION_SHIPCALL_idx` (`shipcall_id` ASC) VISIBLE,
|
||||
DROP INDEX `FK_NOT_PART` ,
|
||||
DROP INDEX `FK_NOT_TIMES` ;
|
||||
;
|
||||
ALTER TABLE `bremen_calling_devel`.`notification`
|
||||
ADD CONSTRAINT `FK_NOTIFICATION_SHIPCALL`
|
||||
FOREIGN KEY (`shipcall_id`)
|
||||
REFERENCES `bremen_calling_devel`.`shipcall` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION;
|
||||
|
||||
|
||||
-- added notification flags
|
||||
-- participant reference is now mandatory
|
||||
|
||||
ALTER TABLE `bremen_calling_devel`.`user`
|
||||
DROP FOREIGN KEY `FK_USER_PART`;
|
||||
ALTER TABLE `bremen_calling_devel`.`user`
|
||||
ADD COLUMN `notify_email` BIT NULL DEFAULT NULL AFTER `api_key`,
|
||||
ADD COLUMN `notify_whatsapp` BIT NULL DEFAULT NULL AFTER `notify_email`,
|
||||
ADD COLUMN `notify_signal` BIT NULL DEFAULT NULL AFTER `notify_whatsapp`,
|
||||
ADD COLUMN `notify_popup` BIT NULL DEFAULT NULL AFTER `notify_signal`,
|
||||
CHANGE COLUMN `participant_id` `participant_id` INT UNSIGNED NOT NULL ;
|
||||
ALTER TABLE `bremen_calling_devel`.`user`
|
||||
ADD CONSTRAINT `FK_USER_PART`
|
||||
FOREIGN KEY (`participant_id`)
|
||||
REFERENCES `bremen_calling_devel`.`participant` (`id`);
|
||||
|
||||
-- History table for change tracking
|
||||
|
||||
CREATE TABLE `bremen_calling_devel`.`history` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`participant_id` INT UNSIGNED NOT NULL,
|
||||
`user_id` INT UNSIGNED NOT NULL,
|
||||
`shipcall_id` INT UNSIGNED NOT NULL,
|
||||
`timestamp` DATETIME NOT NULL COMMENT 'Time of saving',
|
||||
`eta` DATETIME NULL COMMENT 'Current ETA / ETD value (depends if shipcall or times were saved)',
|
||||
`type` INT NOT NULL COMMENT 'shipcall or times',
|
||||
`operation` INT NOT NULL COMMENT 'insert, update or delete',
|
||||
PRIMARY KEY (`id`))
|
||||
COMMENT = 'This table stores a history of changes made to shipcalls so that everyone can see who changed what and when';
|
||||
|
||||
-- and foreign keys
|
||||
|
||||
ALTER TABLE `bremen_calling_devel`.`history`
|
||||
ADD INDEX `FK_HISTORY_PARTICIPANT_idx` (`participant_id` ASC) VISIBLE,
|
||||
ADD INDEX `FK_HISTORY_SHIPCALL_idx` (`shipcall_id` ASC) VISIBLE;
|
||||
;
|
||||
ALTER TABLE `bremen_calling_devel`.`history`
|
||||
ADD CONSTRAINT `FK_HISTORY_PARTICIPANT`
|
||||
FOREIGN KEY (`participant_id`)
|
||||
REFERENCES `bremen_calling_devel`.`participant` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
ADD CONSTRAINT `FK_HISTORY_SHIPCALL`
|
||||
FOREIGN KEY (`shipcall_id`)
|
||||
REFERENCES `bremen_calling_devel`.`shipcall` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
ADD CONSTRAINT `FK_HISTORY_USER`
|
||||
FOREIGN KEY (`user_id`)
|
||||
REFERENCES `bremen_calling_devel`.`user` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION;
|
||||
@ -17,6 +17,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\add.png" />
|
||||
<None Remove="Resources\arrow_down_green.png" />
|
||||
<None Remove="Resources\arrow_down_red.png" />
|
||||
<None Remove="Resources\arrow_right_blue.png" />
|
||||
@ -31,6 +32,7 @@
|
||||
<None Remove="Resources\containership.png" />
|
||||
<None Remove="Resources\delete.png" />
|
||||
<None Remove="Resources\delete2.png" />
|
||||
<None Remove="Resources\edit.png" />
|
||||
<None Remove="Resources\emergency_stop_button.png" />
|
||||
<None Remove="Resources\logo_bremen_calling.png" />
|
||||
<None Remove="Resources\ship2.png" />
|
||||
@ -68,6 +70,7 @@
|
||||
<Generator>OpenApiCodeGenerator</Generator>
|
||||
<LastGenOutput>BreCalApi.cs</LastGenOutput>
|
||||
</None>
|
||||
<Resource Include="Resources\add.png" />
|
||||
<Resource Include="Resources\arrow_down_green.png" />
|
||||
<Resource Include="Resources\arrow_down_red.png" />
|
||||
<Resource Include="Resources\arrow_right_blue.png" />
|
||||
@ -82,6 +85,7 @@
|
||||
<Resource Include="Resources\containership.png" />
|
||||
<Resource Include="Resources\delete.png" />
|
||||
<Resource Include="Resources\delete2.png" />
|
||||
<Resource Include="Resources\edit.png" />
|
||||
<Resource Include="Resources\emergency_stop_button.png" />
|
||||
<Resource Include="Resources\logo_bremen_calling.png" />
|
||||
<Resource Include="Resources\ship2.png" />
|
||||
@ -106,7 +110,7 @@
|
||||
<PackageReference Include="JsonSubTypes" Version="2.0.1" />
|
||||
<PackageReference Include="log4net" Version="2.0.15" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Polly" Version="7.2.4" />
|
||||
<PackageReference Include="Polly" Version="8.2.0" />
|
||||
<PackageReference Include="RestSharp" Version="110.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
258
src/BreCalClient/ENIDataGrid.cs
Normal file
258
src/BreCalClient/ENIDataGrid.cs
Normal file
@ -0,0 +1,258 @@
|
||||
// Copyright (c) 2017 schick Informatik
|
||||
// Description: DataGrid mit etwas "verbesserten" Funktionen
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
|
||||
namespace BreCalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
|
||||
///
|
||||
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
|
||||
/// Add this XmlNamespace attribute to the root element of the markup file where it is
|
||||
/// to be used:
|
||||
///
|
||||
/// xmlns:enictrl="clr-namespace:ENI2.Controls"
|
||||
///
|
||||
///
|
||||
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
|
||||
/// Add this XmlNamespace attribute to the root element of the markup file where it is
|
||||
/// to be used:
|
||||
///
|
||||
/// xmlns:enictrl="clr-namespace:ENI2.Controls;assembly=ENI2.Controls"
|
||||
///
|
||||
/// You will also need to add a project reference from the project where the XAML file lives
|
||||
/// to this project and Rebuild to avoid compilation errors:
|
||||
///
|
||||
/// Right click on the target project in the Solution Explorer and
|
||||
/// "Add Reference"->"Projects"->[Browse to and select this project]
|
||||
///
|
||||
///
|
||||
/// Step 2)
|
||||
/// Go ahead and use your control in the XAML file.
|
||||
///
|
||||
/// <MyNamespace:ENIDataGrid/>
|
||||
///
|
||||
/// </summary>
|
||||
public class ENIDataGrid : DataGrid
|
||||
{
|
||||
|
||||
public event Action<object>? EditRequested;
|
||||
public event Action<object>? DeleteRequested;
|
||||
public event Action? CreateRequested;
|
||||
public event Action? RefreshGrid;
|
||||
|
||||
public event Action<object>? PrintRequested;
|
||||
public event Action<object>? ExportRequested;
|
||||
public event Action<object>? ShowTextRequested;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
|
||||
this.MouseDoubleClick += dataGrid_MouseDoubleClick;
|
||||
this.PreviewKeyDown += ENIDataGrid_PreviewKeyDown;
|
||||
|
||||
this.ContextMenu = new ContextMenu();
|
||||
this.CanUserAddRows = false;
|
||||
this.IsReadOnly = false;
|
||||
|
||||
MenuItem addItem = new MenuItem();
|
||||
|
||||
addItem.Header = BreCalClient.Resources.Resources.textAdd;
|
||||
addItem.Icon = new Image { Source = Util.LoadImage(BreCalClient.Resources.Resources.add) };
|
||||
addItem.Click += new RoutedEventHandler(this.addItem);
|
||||
this.ContextMenu.Items.Add(addItem);
|
||||
|
||||
MenuItem deleteItem = new MenuItem();
|
||||
deleteItem.Header = BreCalClient.Resources.Resources.textDelete;
|
||||
deleteItem.Icon = new Image { Source = Util.LoadImage(BreCalClient.Resources.Resources.delete) };
|
||||
deleteItem.Click += this.deleteItem;
|
||||
this.ContextMenu.Items.Add(deleteItem);
|
||||
|
||||
MenuItem editItem = new MenuItem();
|
||||
editItem.Header = BreCalClient.Resources.Resources.textEdit;
|
||||
editItem.Icon = new Image { Source = Util.LoadImage(BreCalClient.Resources.Resources.edit) };
|
||||
editItem.Click += this.editItem;
|
||||
this.ContextMenu.Items.Add(editItem);
|
||||
}
|
||||
|
||||
private void ENIDataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if(sender is ENIDataGrid)
|
||||
{
|
||||
var grid = sender as ENIDataGrid;
|
||||
if (Key.Delete == e.Key)
|
||||
this.deleteItem(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
#region public
|
||||
|
||||
public DataGridRow GetRow(int index)
|
||||
{
|
||||
DataGridRow row = (DataGridRow)this.ItemContainerGenerator.ContainerFromIndex(index);
|
||||
if(row == null)
|
||||
{
|
||||
this.UpdateLayout();
|
||||
this.ScrollIntoView(this.Items[index]);
|
||||
row = (DataGridRow)this.ItemContainerGenerator.ContainerFromIndex(index);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
public DataGridCell? GetCell(DataGridRow row, int column)
|
||||
{
|
||||
if (row != null)
|
||||
{
|
||||
DataGridCellsPresenter? presenter = GetVisualChild<DataGridCellsPresenter>(row);
|
||||
|
||||
if (presenter == null)
|
||||
{
|
||||
this.ScrollIntoView(row, this.Columns[column]);
|
||||
presenter = GetVisualChild<DataGridCellsPresenter>(row);
|
||||
}
|
||||
|
||||
DataGridCell? cell = (DataGridCell?)presenter?.ItemContainerGenerator.ContainerFromIndex(column);
|
||||
return cell;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public DataGridCell? GetCell(int rowIndex, int columnIndex)
|
||||
{
|
||||
DataGridRow row = this.GetRow(rowIndex);
|
||||
return this.GetCell(row, columnIndex);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region protected
|
||||
|
||||
protected void addItem(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");
|
||||
if (!this.IsReadOnly)
|
||||
{
|
||||
this.CreateRequested?.Invoke();
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected void deleteItem(object? sender, RoutedEventArgs? e)
|
||||
{
|
||||
if((this.SelectedItems != null) && (this.SelectedItems.Count > 0) && !this.IsReadOnly)
|
||||
{
|
||||
MessageBoxResult result = MessageBox.Show("Are your sure?", "Please confirm", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
List<object> deleteList = new List<object>();
|
||||
foreach (object deleteItem in this.SelectedItems)
|
||||
deleteList.Add(deleteItem);
|
||||
|
||||
foreach (object deleteItem in deleteList)
|
||||
{
|
||||
if (deleteItem != null)
|
||||
{
|
||||
this.DeleteRequested?.Invoke(deleteItem);
|
||||
}
|
||||
}
|
||||
|
||||
this.RefreshGrid?.Invoke();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void editItem(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if((this.SelectedItems != null) && (this.SelectedItems.Count == 1) && !this.IsReadOnly)
|
||||
{
|
||||
if (this.SelectedItems[0] is object selectedEntity)
|
||||
this.EditRequested?.Invoke(selectedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
protected void printItem(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if ((this.SelectedItems != null) && (this.SelectedItems.Count == 1) )
|
||||
{
|
||||
if (this.SelectedItems[0] is object selectedEntity)
|
||||
this.PrintRequested?.Invoke(selectedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
protected void exportItem(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if ((this.SelectedItems != null) && (this.SelectedItems.Count == 1))
|
||||
{
|
||||
if (this.SelectedItems[0] is object selectedEntity)
|
||||
this.ExportRequested?.Invoke(selectedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
protected void showTextItem(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if ((this.SelectedItems != null) && (this.SelectedItems.Count == 1))
|
||||
{
|
||||
if (this.SelectedItems[0] is object selectedEntity)
|
||||
this.ShowTextRequested?.Invoke(selectedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region private
|
||||
|
||||
private void dataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender != null)
|
||||
{
|
||||
if ((sender is DataGrid grid) && (grid.SelectedItems != null) && (grid.SelectedItems.Count == 1) && !this.IsReadOnly)
|
||||
{
|
||||
DataGridRow? dgr = grid.ItemContainerGenerator.ContainerFromItem(grid.SelectedItem) as DataGridRow;
|
||||
if (grid.SelectedItem is object selectedEntity)
|
||||
this.EditRequested?.Invoke(selectedEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region private static
|
||||
|
||||
private static T? GetVisualChild<T>(Visual parent) where T : Visual
|
||||
{
|
||||
T? child = default;
|
||||
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (int i = 0; i < numVisuals; i++)
|
||||
{
|
||||
Visual? v = (Visual)VisualTreeHelper.GetChild(parent, i);
|
||||
child = v as T;
|
||||
if (child == null)
|
||||
{
|
||||
child = GetVisualChild<T>(v);
|
||||
}
|
||||
if (child != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
54
src/BreCalClient/EditShipDialog.xaml
Normal file
54
src/BreCalClient/EditShipDialog.xaml
Normal file
@ -0,0 +1,54 @@
|
||||
<Window x:Class="BreCalClient.EditShipDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BreCalClient"
|
||||
xmlns:p = "clr-namespace:BreCalClient.Resources"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
mc:Ignorable="d"
|
||||
Left="{local:SettingBinding W1Left}" Top="{local:SettingBinding W1Top}"
|
||||
Title="{x:Static p:Resources.textEditShip}" Height="250" Width="500" Loaded="Window_Loaded" ResizeMode="NoResize">
|
||||
<Grid x:Name="shipGrid">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width=".3*" />
|
||||
<ColumnDefinition Width=".6*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="28" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="Name" HorizontalAlignment="Right" />
|
||||
<TextBox x:Name="textBoxName" Grid.Column="1" Margin="2" VerticalContentAlignment="Center" Text="{Binding Name, Mode=OneWay}" />
|
||||
<Label Content="{x:Static p:Resources.textTugCompany}" HorizontalAlignment="Right" Grid.Row="1" />
|
||||
<Grid Grid.Row="1" Grid.Column="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="28" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ComboBox x:Name="comboBoxParticipants" Margin="2" DisplayMemberPath="Name" />
|
||||
<Button x:Name="buttonResetParticipant" Grid.Column="1" Margin="2" Click="buttonResetParticipant_Click">
|
||||
<Image Source="./Resources/delete2.png"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Label Content="IMO" HorizontalAlignment="Right" Grid.Row="2" />
|
||||
<xctk:IntegerUpDown Name="integerUpDownIMO" Grid.Column="1" Grid.Row="2" Value="{Binding Imo, Mode=OneWay}" Margin="2" Minimum="1000000" Maximum="9999999" ShowButtonSpinner="False"/>
|
||||
<Label Content="{x:Static p:Resources.textCallsign}" HorizontalAlignment="Right" Grid.Row="3" />
|
||||
<TextBox x:Name="textBoxCallsign" Grid.Column="1" Grid.Row="3" Margin="2" VerticalContentAlignment="Center" Text="{Binding Callsign, Mode=OneWay}" />
|
||||
<Label Content="{x:Static p:Resources.textLength}" HorizontalAlignment="Right" Grid.Row="4" />
|
||||
<xctk:DoubleUpDown Name="doubleUpDownLength" Grid.Row="4" Grid.Column="1" Value="{Binding Length, Mode=OneWay}" Margin="2" Minimum="0" />
|
||||
<Label Content="{x:Static p:Resources.textWidth}" HorizontalAlignment="Right" Grid.Row="5" />
|
||||
<xctk:DoubleUpDown Name="doubleUpDownWidth" Grid.Row="5" Grid.Column="1" Value="{Binding Width, Mode=OneWay}" Margin="2" Minimum="0"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="7" Orientation="Horizontal" FlowDirection="RightToLeft">
|
||||
<Button x:Name="buttonCancel" Width="80" Content="{x:Static p:Resources.textCancel}" Margin="2" Click="buttonCancel_Click" />
|
||||
<Button x:Name="buttonOK" Width="80" Content="OK" Margin="2" Click="buttonOK_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
71
src/BreCalClient/EditShipDialog.xaml.cs
Normal file
71
src/BreCalClient/EditShipDialog.xaml.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using BreCalClient.misc.Model;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace BreCalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for EditShipDialog.xaml
|
||||
/// </summary>
|
||||
public partial class EditShipDialog : Window
|
||||
{
|
||||
public EditShipDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public Ship Ship { get; set; } = new();
|
||||
|
||||
public List<Participant> Participants { get; } = new List<Participant>();
|
||||
|
||||
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.DialogResult = false;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonOK_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
this.Ship.Name = this.textBoxName.Text.Trim();
|
||||
|
||||
if (this.comboBoxParticipants.SelectedItem != null)
|
||||
{
|
||||
this.Ship.ParticipantId = ((Participant)this.comboBoxParticipants.SelectedItem).Id;
|
||||
this.Ship.IsTug = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Ship.IsTug = false;
|
||||
}
|
||||
this.Ship.Imo = this.integerUpDownIMO.Value;
|
||||
this.Ship.Callsign = this.textBoxCallsign.Text.Trim();
|
||||
this.Ship.Length = (float?) this.doubleUpDownLength.Value;
|
||||
this.Ship.Width = (float?) this.doubleUpDownWidth.Value;
|
||||
this.DialogResult = true;
|
||||
this.Close();
|
||||
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.DataContext = this.Ship;
|
||||
this.comboBoxParticipants.ItemsSource = this.Participants;
|
||||
|
||||
if(this.Ship.ParticipantId != null)
|
||||
{
|
||||
foreach(Participant p in this.Participants)
|
||||
{
|
||||
if(this.Ship.ParticipantId == p.Id)
|
||||
this.comboBoxParticipants.SelectedItem = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buttonResetParticipant_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxParticipants.SelectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,15 +32,16 @@
|
||||
<Label Content="{x:Static p:Resources.textShip}" Grid.Column="0" Grid.Row="0" HorizontalContentAlignment="Right"/>
|
||||
<ComboBox x:Name="comboBoxShip" Margin="2" Grid.Column="1" Grid.Row="0" SelectionChanged="comboBoxShip_SelectionChanged" SelectedValuePath="Ship.Id" IsEditable="True" IsTextSearchEnabled="True" IsTextSearchCaseSensitive="False" />
|
||||
<Label Content="IMO" Grid.Column="0" Grid.Row="1" HorizontalContentAlignment="Right"/>
|
||||
<xctk:IntegerUpDown x:Name="integerUpDownIMO" IsReadOnly="True" Margin="2" Grid.Column="1" Grid.Row="1" ShowButtonSpinner="False"/>
|
||||
<xctk:IntegerUpDown x:Name="integerUpDownIMO" IsReadOnly="True" Margin="2" Grid.Column="1" Grid.Row="1" ShowButtonSpinner="False" IsEnabled="False"/>
|
||||
<Label Content="{x:Static p:Resources.textCallsign}" Grid.Column="0" Grid.Row="2" HorizontalContentAlignment="Right"/>
|
||||
<TextBox x:Name="textBoxCallsign" IsReadOnly="True" Grid.Column="1" Grid.Row="2" Margin="2" />
|
||||
<TextBox x:Name="textBoxCallsign" IsReadOnly="True" Grid.Column="1" Grid.Row="2" Margin="2" IsEnabled="False"/>
|
||||
<Label Content="{x:Static p:Resources.textLength}" Grid.Column="0" Grid.Row="3" HorizontalContentAlignment="Right"/>
|
||||
<xctk:DoubleUpDown x:Name="doubleUpDownLength" Margin="2" Grid.Column="1" Grid.Row="3" FormatString="N2" IsReadOnly="True" />
|
||||
<xctk:DoubleUpDown x:Name="doubleUpDownLength" Margin="2" Grid.Column="1" Grid.Row="3" FormatString="N2" IsReadOnly="True" IsEnabled="False" ShowButtonSpinner="False"/>
|
||||
<Label Content="{x:Static p:Resources.textWidth}" Grid.Column="0" Grid.Row="4" HorizontalContentAlignment="Right"/>
|
||||
<xctk:DoubleUpDown x:Name="doubleUpDownWidth" Margin="2" Grid.Column="1" Grid.Row="4" FormatString="N2" IsReadOnly="True" />
|
||||
<xctk:DoubleUpDown x:Name="doubleUpDownWidth" Margin="2" Grid.Column="1" Grid.Row="4" FormatString="N2" IsReadOnly="True" IsEnabled="False" ShowButtonSpinner="False"/>
|
||||
<Label Content="{x:Static p:Resources.textCancelled}" Grid.Column="0" Grid.Row="5" HorizontalContentAlignment="Right" />
|
||||
<CheckBox x:Name="checkBoxCancelled" Grid.Column="1" Grid.Row="5" Margin="2" VerticalContentAlignment="Center" />
|
||||
<Button x:Name="buttonEditShips" Grid.Column="1" Grid.Row="6" Margin="2" Content="{x:Static p:Resources.textEditShips}" Click="buttonEditShips_Click" Visibility="Hidden" />
|
||||
|
||||
<Label Content="{x:Static p:Resources.textType}" Grid.Column="2" Grid.Row="0" HorizontalContentAlignment="Right" />
|
||||
<Label Content="ETA" Grid.Column="2" Grid.Row="2" HorizontalContentAlignment="Right"/>
|
||||
@ -73,7 +74,7 @@
|
||||
</ComboBox.ContextMenu>
|
||||
</ComboBox>
|
||||
|
||||
<Label x:Name="labelBSMDGranted" Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="2" Content="{x:Static p:Resources.textBSMDGranted}" Visibility="Hidden" FontWeight="DemiBold" />
|
||||
<Label x:Name="labelBSMDGranted" Grid.Row="5" Grid.Column="3" Grid.ColumnSpan="1" Content="{x:Static p:Resources.textBSMDGranted}" Visibility="Hidden" FontWeight="DemiBold" />
|
||||
<StackPanel Grid.Row="6" Grid.Column="3" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Width= "80" Margin="2" Content="{x:Static p:Resources.textOK}" x:Name="buttonOK" Click="buttonOK_Click" IsEnabled="False" />
|
||||
<Button Width="80" Margin="2" Content="{x:Static p:Resources.textCancel}" x:Name="buttonCancel" Click="buttonCancel_Click"/>
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// Description: Windows dialog to create / edit ship calls
|
||||
//
|
||||
|
||||
using BreCalClient.misc.Api;
|
||||
using BreCalClient.misc.Model;
|
||||
using System;
|
||||
using System.Windows;
|
||||
@ -31,6 +32,14 @@ namespace BreCalClient
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShipEditingEnabled
|
||||
{
|
||||
get { return this.buttonEditShips.Visibility == Visibility.Visible; }
|
||||
set { this.buttonEditShips.Visibility = value ? Visibility.Visible : Visibility.Hidden; }
|
||||
}
|
||||
|
||||
public ShipApi ShipApi { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handler
|
||||
@ -39,8 +48,8 @@ namespace BreCalClient
|
||||
{
|
||||
this.comboBoxAgency.ItemsSource = BreCalLists.Participants_Agent;
|
||||
|
||||
this.comboBoxShip.ItemsSource = BreCalLists.Ships;
|
||||
this.comboBoxCategories.ItemsSource = Enum.GetValues(typeof(TypeEnum));
|
||||
this.comboBoxShip.ItemsSource = BreCalLists.AllShips;
|
||||
this.comboBoxCategories.ItemsSource = Enum.GetValues(typeof(ShipcallType));
|
||||
this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
|
||||
this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
|
||||
|
||||
@ -91,12 +100,12 @@ namespace BreCalClient
|
||||
|
||||
private void comboBoxCategories_SelectionChanged(object? sender, SelectionChangedEventArgs? e)
|
||||
{
|
||||
TypeEnum? type = this.comboBoxCategories.SelectedItem as TypeEnum?;
|
||||
ShipcallType? type = this.comboBoxCategories.SelectedItem as ShipcallType?;
|
||||
if (type != null)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TypeEnum.Incoming:
|
||||
case ShipcallType.Arrival:
|
||||
this.datePickerETA.IsEnabled = true;
|
||||
this.datePickerETD.IsEnabled = false;
|
||||
this.datePickerETD.Value = null;
|
||||
@ -104,7 +113,7 @@ namespace BreCalClient
|
||||
this.comboBoxDepartureBerth.IsEnabled = false;
|
||||
this.comboBoxArrivalBerth.IsEnabled = true;
|
||||
break;
|
||||
case TypeEnum.Outgoing:
|
||||
case ShipcallType.Departure:
|
||||
this.datePickerETA.IsEnabled = false;
|
||||
this.datePickerETD.IsEnabled = true;
|
||||
this.datePickerETA.Value = null;
|
||||
@ -112,7 +121,7 @@ namespace BreCalClient
|
||||
this.comboBoxArrivalBerth.IsEnabled = false;
|
||||
this.comboBoxDepartureBerth.IsEnabled = true;
|
||||
break;
|
||||
case TypeEnum.Shifting:
|
||||
case ShipcallType.Shifting:
|
||||
this.datePickerETA.IsEnabled = true;
|
||||
this.datePickerETD.IsEnabled = true;
|
||||
this.comboBoxArrivalBerth.IsEnabled = true;
|
||||
@ -150,18 +159,18 @@ namespace BreCalClient
|
||||
}
|
||||
else
|
||||
{
|
||||
TypeEnum callType = (TypeEnum)comboBoxCategories.SelectedItem;
|
||||
ShipcallType callType = (ShipcallType)comboBoxCategories.SelectedItem;
|
||||
switch (callType)
|
||||
{
|
||||
case TypeEnum.Outgoing:
|
||||
case ShipcallType.Departure:
|
||||
isEnabled &= this.comboBoxDepartureBerth.SelectedItem != null;
|
||||
isEnabled &= this.datePickerETD.Value.HasValue;
|
||||
break;
|
||||
case TypeEnum.Incoming:
|
||||
case ShipcallType.Arrival:
|
||||
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
|
||||
isEnabled &= this.datePickerETA.Value.HasValue;
|
||||
break;
|
||||
case TypeEnum.Shifting:
|
||||
case ShipcallType.Shifting:
|
||||
isEnabled &= ((this.comboBoxDepartureBerth.SelectedItem != null) && (this.comboBoxArrivalBerth.SelectedItem != null));
|
||||
isEnabled &= this.datePickerETD.Value.HasValue;
|
||||
isEnabled &= this.datePickerETA.Value.HasValue;
|
||||
@ -178,7 +187,7 @@ namespace BreCalClient
|
||||
{
|
||||
if (this.ShipcallModel.Shipcall != null)
|
||||
{
|
||||
this.ShipcallModel.Shipcall.Type = (int)this.comboBoxCategories.SelectedItem;
|
||||
this.ShipcallModel.Shipcall.Type = (ShipcallType) this.comboBoxCategories.SelectedItem;
|
||||
this.ShipcallModel.Shipcall.Eta = this.datePickerETA.Value;
|
||||
this.ShipcallModel.Shipcall.Etd = this.datePickerETD.Value;
|
||||
|
||||
@ -186,7 +195,7 @@ namespace BreCalClient
|
||||
this.ShipcallModel.Ship = ((ShipModel)this.comboBoxShip.SelectedItem).Ship;
|
||||
this.ShipcallModel.Shipcall.Canceled = this.checkBoxCancelled.IsChecked;
|
||||
|
||||
if (this.ShipcallModel.Shipcall.Type != 3) // incoming, outgoing
|
||||
if (this.ShipcallModel.Shipcall.Type != ShipcallType.Shifting) // incoming, outgoing
|
||||
{
|
||||
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
|
||||
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
|
||||
@ -204,6 +213,7 @@ namespace BreCalClient
|
||||
ParticipantAssignment pa = new()
|
||||
{
|
||||
ParticipantId = participant.Id,
|
||||
|
||||
Type = (int)Extensions.ParticipantType.AGENCY
|
||||
};
|
||||
this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.AGENCY] = pa;
|
||||
@ -253,7 +263,7 @@ namespace BreCalClient
|
||||
if (this.ShipcallModel == null) return;
|
||||
if (this.ShipcallModel.Shipcall != null)
|
||||
{
|
||||
this.comboBoxCategories.SelectedItem = (TypeEnum)this.ShipcallModel.Shipcall.Type;
|
||||
this.comboBoxCategories.SelectedItem = this.ShipcallModel.Shipcall.Type;
|
||||
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
|
||||
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
|
||||
// this.textBoxVoyage.Text = this.ShipcallModel.Shipcall.Voyage;
|
||||
@ -261,7 +271,7 @@ namespace BreCalClient
|
||||
this.comboBoxShip.SelectedValue = this.ShipcallModel.Shipcall.ShipId;
|
||||
this.checkBoxCancelled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
|
||||
|
||||
if (this.ShipcallModel.Shipcall.Type != 3) // incoming, outgoing
|
||||
if (this.ShipcallModel.Shipcall.Type != ShipcallType.Shifting) // incoming, outgoing
|
||||
{
|
||||
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
|
||||
this.comboBoxDepartureBerth.SelectedValue = this.ShipcallModel.Shipcall.DepartureBerthId;
|
||||
@ -342,6 +352,20 @@ namespace BreCalClient
|
||||
this.CheckForCompletion();
|
||||
}
|
||||
|
||||
private void buttonEditShips_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ShipListDialog shipListDialog = new()
|
||||
{
|
||||
ShipApi = this.ShipApi
|
||||
};
|
||||
|
||||
shipListDialog.ShowDialog();
|
||||
|
||||
// reload combobox
|
||||
this.comboBoxShip.ItemsSource = null;
|
||||
this.comboBoxShip.ItemsSource = BreCalLists.AllShips;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ namespace BreCalClient
|
||||
|
||||
public Times Times { get; set; } = new();
|
||||
|
||||
public Extensions.TypeEnum CallType { get; set; }
|
||||
public ShipcallType CallType { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ namespace BreCalClient
|
||||
|
||||
public Times Times { get; set; } = new();
|
||||
|
||||
public Extensions.TypeEnum CallType { get; set; }
|
||||
public ShipcallType CallType { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ namespace BreCalClient
|
||||
|
||||
public Times Times { get; set; } = new();
|
||||
|
||||
public Extensions.TypeEnum CallType { get; set; }
|
||||
public ShipcallType CallType { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ namespace BreCalClient
|
||||
|
||||
public Times Times { get; set; } = new();
|
||||
|
||||
public Extensions.TypeEnum CallType { get; set; }
|
||||
public ShipcallType CallType { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@ -75,12 +75,12 @@ namespace BreCalClient
|
||||
|
||||
switch (CallType)
|
||||
{
|
||||
case Extensions.TypeEnum.Incoming:
|
||||
case ShipcallType.Arrival:
|
||||
this.labelETA.FontWeight = FontWeights.Bold;
|
||||
this.datePickerETABerth.ContextMenu.IsEnabled = false;
|
||||
break;
|
||||
case Extensions.TypeEnum.Outgoing:
|
||||
case Extensions.TypeEnum.Shifting:
|
||||
case ShipcallType.Departure:
|
||||
case ShipcallType.Shifting:
|
||||
this.labelETD.FontWeight = FontWeights.Bold;
|
||||
this.datePickerETDBerth.ContextMenu.IsEnabled = false;
|
||||
break;
|
||||
@ -89,7 +89,7 @@ namespace BreCalClient
|
||||
|
||||
private void EnableControls()
|
||||
{
|
||||
Extensions.ParticipantType pType = (Extensions.ParticipantType) (this.Times.ParticipantType ?? 0);
|
||||
Extensions.ParticipantType pType = (Extensions.ParticipantType) this.Times.ParticipantType;
|
||||
if (this.Times.ParticipantId != App.Participant.Id) return; // if this is not "my" entry, there is no editing!
|
||||
|
||||
switch (pType)
|
||||
@ -97,24 +97,24 @@ namespace BreCalClient
|
||||
case Extensions.ParticipantType.MOORING:
|
||||
case Extensions.ParticipantType.PORT_ADMINISTRATION:
|
||||
case Extensions.ParticipantType.TUG:
|
||||
this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.datePickerETABerth.IsEnabled = (CallType == ShipcallType.Arrival);
|
||||
//this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerETDBerth.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerETDBerth.IsEnabled = (CallType == ShipcallType.Departure || CallType == ShipcallType.Shifting);
|
||||
//this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerLockTime.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerLockTime.IsEnabled = (CallType == ShipcallType.Arrival || CallType == ShipcallType.Shifting);
|
||||
//this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerZoneEntry.IsEnabled = false;
|
||||
//this.checkBoxZoneEntryFixed.IsEnabled = false;
|
||||
this.textBoxRemarks.IsEnabled = true;
|
||||
break;
|
||||
case Extensions.ParticipantType.PILOT:
|
||||
this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.datePickerETABerth.IsEnabled = (CallType == ShipcallType.Arrival);
|
||||
//this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerETDBerth.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerETDBerth.IsEnabled = (CallType == ShipcallType.Departure || CallType == ShipcallType.Shifting);
|
||||
//this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerLockTime.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerLockTime.IsEnabled = (CallType == ShipcallType.Arrival || CallType == ShipcallType.Shifting);
|
||||
//this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
|
||||
this.datePickerZoneEntry.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.datePickerZoneEntry.IsEnabled = (CallType == ShipcallType.Arrival);
|
||||
//this.checkBoxZoneEntryFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.textBoxRemarks.IsEnabled = true;
|
||||
break;
|
||||
|
||||
@ -21,7 +21,7 @@ namespace BreCalClient
|
||||
|
||||
public Times Times { get; set; } = new();
|
||||
|
||||
public Extensions.TypeEnum CallType { get; set; }
|
||||
public ShipcallType CallType { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@ -72,12 +72,12 @@ namespace BreCalClient
|
||||
|
||||
private void CopyToModel()
|
||||
{
|
||||
switch(this.comboBoxPierside.SelectedIndex)
|
||||
this.Times.PierSide = this.comboBoxPierside.SelectedIndex switch
|
||||
{
|
||||
case 0: this.Times.PierSide = true; break;
|
||||
case 1: this.Times.PierSide= false; break;
|
||||
default: this.Times.PierSide = null; break;
|
||||
}
|
||||
0 => true,
|
||||
1 => false,
|
||||
_ => null,
|
||||
};
|
||||
this.Times.OperationsStart = this.datePickerOperationStart.Value;
|
||||
this.Times.OperationsEnd = this.datePickerOperationEnd.Value;
|
||||
this.Times.BerthId = (this.comboBoxBerth.SelectedItem != null) ? ((Berth)this.comboBoxBerth.SelectedItem).Id : null;
|
||||
@ -97,12 +97,12 @@ namespace BreCalClient
|
||||
|
||||
switch (CallType)
|
||||
{
|
||||
case Extensions.TypeEnum.Incoming:
|
||||
case ShipcallType.Arrival:
|
||||
this.labelStart.FontWeight = FontWeights.Bold;
|
||||
this.datePickerOperationStart.ContextMenu.IsEnabled = false;
|
||||
break;
|
||||
case Extensions.TypeEnum.Outgoing:
|
||||
case Extensions.TypeEnum.Shifting:
|
||||
case ShipcallType.Departure:
|
||||
case ShipcallType.Shifting:
|
||||
this.labelEnd.FontWeight = FontWeights.Bold;
|
||||
this.datePickerOperationEnd.ContextMenu.IsEnabled = false;
|
||||
break;
|
||||
@ -114,11 +114,11 @@ namespace BreCalClient
|
||||
{
|
||||
if (this.Times.ParticipantId != App.Participant.Id) return;
|
||||
|
||||
this.datePickerOperationStart.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.datePickerOperationEnd.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing) || (CallType == Extensions.TypeEnum.Shifting);
|
||||
this.comboBoxBerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.comboBoxPierside.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.textBoxBerthRemarks.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
|
||||
this.datePickerOperationStart.IsEnabled = CallType == ShipcallType.Arrival;
|
||||
this.datePickerOperationEnd.IsEnabled = (CallType == ShipcallType.Departure) || (CallType == ShipcallType.Shifting);
|
||||
this.comboBoxBerth.IsEnabled = CallType == ShipcallType.Arrival;
|
||||
this.comboBoxPierside.IsEnabled = CallType == ShipcallType.Arrival;
|
||||
this.textBoxBerthRemarks.IsEnabled = CallType == ShipcallType.Arrival;
|
||||
this.textBoxRemarks.IsEnabled = true;
|
||||
this.buttonOK.IsEnabled = true;
|
||||
}
|
||||
|
||||
@ -47,16 +47,6 @@ namespace BreCalClient
|
||||
ALLOW_BSMD = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should actually be defined in yaml
|
||||
/// </summary>
|
||||
public enum TypeEnum
|
||||
{
|
||||
Incoming = 1,
|
||||
Outgoing = 2,
|
||||
Shifting = 3
|
||||
}
|
||||
|
||||
public enum SortOrder
|
||||
{
|
||||
SHIP_NAME,
|
||||
@ -81,15 +71,15 @@ namespace BreCalClient
|
||||
public static string Truncate(this string value, int maxLength)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return value;
|
||||
return value.Length <= maxLength ? value : value.Substring(0, maxLength);
|
||||
return value.Length <= maxLength ? value : value[..maxLength];
|
||||
}
|
||||
|
||||
public static string TruncateDots(this string value, int maxLength)
|
||||
{
|
||||
if(string.IsNullOrEmpty(value)) return value;
|
||||
if (value.Length <= maxLength) return value;
|
||||
if (value.Length > (maxLength + 1)) return $"{value.Substring(0, maxLength)}..";
|
||||
return value.Substring(0, maxLength);
|
||||
if (value.Length > (maxLength + 1)) return $"{value[..maxLength]}..";
|
||||
return value[..maxLength];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -13,7 +13,7 @@ namespace BreCalClient
|
||||
|
||||
string Title { get; set; }
|
||||
|
||||
Extensions.TypeEnum CallType { get; set; }
|
||||
ShipcallType CallType { get; set; }
|
||||
|
||||
bool? ShowDialog();
|
||||
|
||||
|
||||
@ -18,11 +18,11 @@ using BreCalClient.misc.Model;
|
||||
using static BreCalClient.Extensions;
|
||||
using System.Collections.Concurrent;
|
||||
using Newtonsoft.Json;
|
||||
using System.Security.Principal;
|
||||
|
||||
using Polly;
|
||||
using System.Net.Http;
|
||||
using System.Net;
|
||||
using Polly.Retry;
|
||||
|
||||
|
||||
namespace BreCalClient
|
||||
{
|
||||
@ -45,7 +45,12 @@ namespace BreCalClient
|
||||
private readonly ConcurrentDictionary<int, ShipcallControl> _allShipCallsControlDict = new();
|
||||
private readonly List<ShipcallControlModel> _visibleControlModels = new();
|
||||
|
||||
private readonly DefaultApi _api;
|
||||
private readonly ShipcallApi _shipcallApi;
|
||||
private readonly UserApi _userApi;
|
||||
private readonly TimesApi _timesApi;
|
||||
private readonly StaticApi _staticApi;
|
||||
private readonly ShipApi _shipApi;
|
||||
|
||||
private CancellationTokenSource _tokenSource = new();
|
||||
private LoginResult? _loginResult;
|
||||
private bool _refreshImmediately = false;
|
||||
@ -75,8 +80,16 @@ namespace BreCalClient
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
_api = new DefaultApi(Properties.Settings.Default.API_URL);
|
||||
_api.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
|
||||
_userApi = new UserApi(Properties.Settings.Default.API_URL);
|
||||
_userApi.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
|
||||
_shipcallApi = new ShipcallApi(Properties.Settings.Default.API_URL);
|
||||
_shipcallApi.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
|
||||
_timesApi = new TimesApi(Properties.Settings.Default.API_URL);
|
||||
_timesApi.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
|
||||
_staticApi = new StaticApi(Properties.Settings.Default.API_URL);
|
||||
_staticApi.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
|
||||
_shipApi = new ShipApi(Properties.Settings.Default.API_URL);
|
||||
_shipApi.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
|
||||
|
||||
const int maxDelayInMilliseconds = 32 * 1000;
|
||||
var jitterer = new Random();
|
||||
@ -140,13 +153,17 @@ namespace BreCalClient
|
||||
|
||||
try
|
||||
{
|
||||
_loginResult = await _api.LoginPostAsync(_credentials);
|
||||
_loginResult = await _userApi.LoginAsync(_credentials);
|
||||
if (_loginResult != null)
|
||||
{
|
||||
if (_loginResult.Id > 0)
|
||||
{
|
||||
this.busyIndicator.IsBusy = false;
|
||||
this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._userApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._shipcallApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._timesApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._staticApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._shipApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this.LoadStaticLists();
|
||||
this.labelUsername.Text = $"{_loginResult.FirstName} {_loginResult.LastName}";
|
||||
}
|
||||
@ -179,12 +196,16 @@ namespace BreCalClient
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
_loginResult = _api.LoginPost(_credentials);
|
||||
_loginResult = _userApi.Login(_credentials);
|
||||
if (_loginResult != null)
|
||||
{
|
||||
if (_loginResult.Id > 0)
|
||||
{
|
||||
this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._userApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._timesApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._shipcallApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._staticApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
this._shipApi.Configuration.ApiKey["Authorization"] = _loginResult.Token;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
@ -212,7 +233,11 @@ namespace BreCalClient
|
||||
|
||||
private void NewWithModel(ShipcallControlModel? model)
|
||||
{
|
||||
EditShipcallControl esc = new();
|
||||
EditShipcallControl esc = new()
|
||||
{
|
||||
ShipEditingEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD),
|
||||
ShipApi = _shipApi
|
||||
};
|
||||
if (model != null)
|
||||
esc.ShipcallModel = model;
|
||||
|
||||
@ -228,7 +253,7 @@ namespace BreCalClient
|
||||
esc.ShipcallModel.Shipcall?.Participants.Add(pa);
|
||||
try
|
||||
{
|
||||
this._api.ShipcallsPost(esc.ShipcallModel.Shipcall); // save new ship call
|
||||
this._shipcallApi.ShipcallCreate(esc.ShipcallModel.Shipcall); // save new ship call
|
||||
this.AddShipcall(esc.ShipcallModel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -240,11 +265,11 @@ namespace BreCalClient
|
||||
_tokenSource.Cancel(); // force timer loop end
|
||||
|
||||
// if this was an arrival, create the matching departure call and open it
|
||||
if (esc.ShipcallModel.Shipcall?.Type == (int)Extensions.TypeEnum.Incoming)
|
||||
if (esc.ShipcallModel.Shipcall?.Type == ShipcallType.Arrival)
|
||||
{
|
||||
ShipcallControlModel scmOut = new();
|
||||
scmOut.Shipcall = new();
|
||||
scmOut.Shipcall.Type = (int)Extensions.TypeEnum.Outgoing;
|
||||
scmOut.Shipcall.Type = ShipcallType.Departure;
|
||||
scmOut.Shipcall.ShipId = esc.ShipcallModel.Shipcall.ShipId;
|
||||
scmOut.Ship = esc.ShipcallModel.Ship;
|
||||
DateTime eta = esc.ShipcallModel.Shipcall?.Eta ?? DateTime.Now;
|
||||
@ -283,7 +308,7 @@ namespace BreCalClient
|
||||
};
|
||||
try
|
||||
{
|
||||
await _api.UserPutAsync(ud);
|
||||
await _userApi.UserUpdateAsync(ud);
|
||||
MessageBox.Show(BreCalClient.Resources.Resources.textPasswordChanged, BreCalClient.Resources.Resources.textConfirmation, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -330,9 +355,9 @@ namespace BreCalClient
|
||||
|
||||
private async void LoadStaticLists()
|
||||
{
|
||||
BreCalLists.InitializeBerths(await _api.BerthsGetAsync());
|
||||
BreCalLists.InitializeShips(await _api.ShipsGetAsync());
|
||||
BreCalLists.InitializeParticipants(await _api.ParticipantsGetAsync());
|
||||
BreCalLists.InitializeBerths(await _staticApi.BerthsGetAsync());
|
||||
BreCalLists.InitializeShips(await _shipApi.ShipsGetAsync());
|
||||
BreCalLists.InitializeParticipants(await _staticApi.ParticipantsGetAsync());
|
||||
|
||||
this.searchFilterControl.SetBerths(BreCalLists.Berths);
|
||||
|
||||
@ -372,9 +397,9 @@ namespace BreCalClient
|
||||
try
|
||||
{
|
||||
if(this.searchPastDays != 0)
|
||||
shipcalls = await _api.ShipcallsGetAsync(this.searchPastDays);
|
||||
shipcalls = await _shipcallApi.ShipcallsGetAsync(this.searchPastDays);
|
||||
else
|
||||
shipcalls = await _api.ShipcallsGetAsync();
|
||||
shipcalls = await _shipcallApi.ShipcallsGetAsync();
|
||||
|
||||
this.Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
@ -401,7 +426,7 @@ namespace BreCalClient
|
||||
foreach (Shipcall shipcall in shipcalls)
|
||||
{
|
||||
// load times for each shipcall
|
||||
List<Times> currentTimes = await _api.TimesGetAsync(shipcall.Id);
|
||||
List<Times> currentTimes = await _timesApi.TimesGetAsync(shipcall.Id);
|
||||
|
||||
if(!_allShipcallsDict.ContainsKey(shipcall.Id))
|
||||
{
|
||||
@ -456,7 +481,8 @@ namespace BreCalClient
|
||||
Shipcall shipcall = scm.Shipcall;
|
||||
if (BreCalLists.ShipLookupDict.ContainsKey(shipcall.ShipId))
|
||||
scm.Ship = BreCalLists.ShipLookupDict[shipcall.ShipId].Ship;
|
||||
if (shipcall.Type == 1)
|
||||
|
||||
if (shipcall.Type == ShipcallType.Arrival)
|
||||
{
|
||||
if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
|
||||
scm.Berth = BreCalLists.BerthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
|
||||
@ -489,7 +515,8 @@ namespace BreCalClient
|
||||
Shipcall shipcall = scm.Shipcall;
|
||||
if (BreCalLists.ShipLookupDict.ContainsKey(shipcall.ShipId))
|
||||
scm.Ship = BreCalLists.ShipLookupDict[shipcall.ShipId].Ship;
|
||||
if (shipcall.Type == 1)
|
||||
|
||||
if (shipcall.Type == ShipcallType.Arrival)
|
||||
{
|
||||
if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
|
||||
scm.Berth = BreCalLists.BerthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
|
||||
@ -543,8 +570,8 @@ namespace BreCalClient
|
||||
|
||||
if(sfm.Berths.Count > 0 )
|
||||
{
|
||||
this._visibleControlModels.RemoveAll(x => (!sfm.Berths.Contains((x.Shipcall?.ArrivalBerthId) ?? -1) && (x.Shipcall?.Type == (int) Extensions.TypeEnum.Incoming)) ||
|
||||
(!sfm.Berths.Contains((x.Shipcall?.DepartureBerthId) ?? -1) && (x.Shipcall?.Type != (int) Extensions.TypeEnum.Incoming)));
|
||||
this._visibleControlModels.RemoveAll(x => (!sfm.Berths.Contains((x.Shipcall?.ArrivalBerthId) ?? -1) && (x.Shipcall?.Type == ShipcallType.Arrival)) ||
|
||||
(!sfm.Berths.Contains((x.Shipcall?.DepartureBerthId) ?? -1) && (x.Shipcall?.Type != ShipcallType.Arrival)));
|
||||
}
|
||||
|
||||
if(sfm.Agencies.Count > 0 )
|
||||
@ -562,7 +589,7 @@ namespace BreCalClient
|
||||
|
||||
if(sfm.Categories.Count > 0 )
|
||||
{
|
||||
_ = this._visibleControlModels.RemoveAll(x => !sfm.Categories.Contains((x.Shipcall?.Type) ?? -1));
|
||||
_ = this._visibleControlModels.RemoveAll(x => { if (x.Shipcall == null) return false; else return !sfm.Categories.Contains(x.Shipcall.Type); });
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(sfm.SearchString))
|
||||
@ -608,8 +635,8 @@ namespace BreCalClient
|
||||
{
|
||||
if (x.Shipcall == null) return 0;
|
||||
if (y.Shipcall == null) return 0;
|
||||
DateTime xDate = (x.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? x.Eta ?? DateTime.Now : x.Etd ?? DateTime.Now;
|
||||
DateTime yDate = (y.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? y.Eta ?? DateTime.Now : y.Etd ?? DateTime.Now;
|
||||
DateTime xDate = (x.Shipcall.Type == ShipcallType.Arrival) ? x.Eta ?? DateTime.Now : x.Etd ?? DateTime.Now;
|
||||
DateTime yDate = (y.Shipcall.Type == ShipcallType.Arrival) ? y.Eta ?? DateTime.Now : y.Etd ?? DateTime.Now;
|
||||
return DateTime.Compare(xDate, yDate);
|
||||
});
|
||||
break;
|
||||
@ -665,7 +692,9 @@ namespace BreCalClient
|
||||
{
|
||||
EditShipcallControl esc = new()
|
||||
{
|
||||
ShipcallModel = obj.ShipcallControlModel
|
||||
ShipcallModel = obj.ShipcallControlModel,
|
||||
ShipApi = _shipApi,
|
||||
ShipEditingEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD)
|
||||
};
|
||||
|
||||
if(esc.ShowDialog() ?? false)
|
||||
@ -673,10 +702,10 @@ namespace BreCalClient
|
||||
try
|
||||
{
|
||||
obj.ShipcallControlModel.Shipcall?.Participants.Clear();
|
||||
obj.ShipcallControlModel.UpdateTimesAssignments(this._api);
|
||||
obj.ShipcallControlModel.UpdateTimesAssignments(this._timesApi);
|
||||
foreach(ParticipantAssignment pa in obj.ShipcallControlModel.AssignedParticipants.Values)
|
||||
obj.ShipcallControlModel.Shipcall?.Participants.Add(pa);
|
||||
await _api.ShipcallsPutAsync(obj.ShipcallControlModel.Shipcall);
|
||||
await _shipcallApi.ShipcallUpdateAsync(obj.ShipcallControlModel.Shipcall);
|
||||
obj.RefreshData();
|
||||
_refreshImmediately = true;
|
||||
_tokenSource.Cancel();
|
||||
@ -689,7 +718,7 @@ namespace BreCalClient
|
||||
}
|
||||
}
|
||||
|
||||
private async void Sc_EditTimesRequested(ShipcallControl obj, Times? times, Extensions.ParticipantType participantType)
|
||||
private async void Sc_EditTimesRequested(ShipcallControl obj, Times? times, ParticipantType participantType)
|
||||
{
|
||||
|
||||
if( obj.ShipcallControlModel == null) { return; }
|
||||
@ -700,7 +729,7 @@ namespace BreCalClient
|
||||
etc.Title = obj.ShipcallControlModel.Title;
|
||||
|
||||
if(obj.ShipcallControlModel.Shipcall != null)
|
||||
etc.CallType = (TypeEnum) obj.ShipcallControlModel.Shipcall.Type;
|
||||
etc.CallType = (ShipcallType) obj.ShipcallControlModel.Shipcall.Type;
|
||||
|
||||
bool wasEdit = false;
|
||||
if (times != null)
|
||||
@ -725,7 +754,7 @@ namespace BreCalClient
|
||||
{
|
||||
if (wasEdit)
|
||||
{
|
||||
await _api.TimesPutAsync(etc.Times);
|
||||
await _timesApi.TimesUpdateAsync(etc.Times);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -734,7 +763,7 @@ namespace BreCalClient
|
||||
{
|
||||
etc.Times.ShipcallId = obj.ShipcallControlModel.Shipcall.Id;
|
||||
}
|
||||
Id apiResultId = await _api.TimesPostAsync(etc.Times);
|
||||
Id apiResultId = await _timesApi.TimesCreateAsync(etc.Times);
|
||||
etc.Times.Id = apiResultId.VarId;
|
||||
obj.ShipcallControlModel?.Times.Add(etc.Times);
|
||||
}
|
||||
@ -753,13 +782,13 @@ namespace BreCalClient
|
||||
IEditShipcallTimesControl? editControl = null;
|
||||
switch(sc.ShipcallControlModel?.Shipcall?.Type)
|
||||
{
|
||||
case (int)TypeEnum.Incoming:
|
||||
case ShipcallType.Arrival:
|
||||
editControl = new EditTimesAgencyIncomingControl();
|
||||
break;
|
||||
case (int)TypeEnum.Outgoing:
|
||||
case ShipcallType.Departure:
|
||||
editControl = new EditTimesAgencyOutgoingControl();
|
||||
break;
|
||||
case (int)TypeEnum.Shifting:
|
||||
case ShipcallType.Shifting:
|
||||
editControl = new EditTimesAgencyShiftingControl();
|
||||
break;
|
||||
}
|
||||
@ -783,7 +812,7 @@ namespace BreCalClient
|
||||
{
|
||||
try
|
||||
{
|
||||
sc.ShipcallControlModel?.UpdateTimesAssignments(_api); // if the agent changed the assignment of the participant to another
|
||||
sc.ShipcallControlModel?.UpdateTimesAssignments(_timesApi); // if the agent changed the assignment of the participant to another
|
||||
|
||||
// always try to be the agent, even if we are BSMD
|
||||
if (editControl.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
|
||||
@ -797,7 +826,7 @@ namespace BreCalClient
|
||||
|
||||
if (wasEdit)
|
||||
{
|
||||
await _api.TimesPutAsync(editControl.Times);
|
||||
await _timesApi.TimesUpdateAsync(editControl.Times);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -805,7 +834,7 @@ namespace BreCalClient
|
||||
{
|
||||
editControl.Times.ShipcallId = sc.ShipcallControlModel.Shipcall.Id;
|
||||
}
|
||||
Id resultAPI_Id = await _api.TimesPostAsync(editControl.Times);
|
||||
Id resultAPI_Id = await _timesApi.TimesCreateAsync(editControl.Times);
|
||||
editControl.Times.Id = resultAPI_Id.VarId;
|
||||
|
||||
sc.ShipcallControlModel?.Times.Add(editControl.Times);
|
||||
@ -813,7 +842,7 @@ namespace BreCalClient
|
||||
editControl.ShipcallModel.Shipcall?.Participants.Clear();
|
||||
foreach (ParticipantAssignment pa in editControl.ShipcallModel.AssignedParticipants.Values)
|
||||
editControl.ShipcallModel.Shipcall?.Participants.Add(pa);
|
||||
await _api.ShipcallsPutAsync(editControl.ShipcallModel.Shipcall);
|
||||
await _shipcallApi.ShipcallUpdateAsync(editControl.ShipcallModel.Shipcall);
|
||||
_refreshImmediately = true;
|
||||
_tokenSource.Cancel();
|
||||
}
|
||||
|
||||
83
src/BreCalClient/Resources/Resources.Designer.cs
generated
83
src/BreCalClient/Resources/Resources.Designer.cs
generated
@ -60,6 +60,16 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
public static byte[] add {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("add", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
@ -180,6 +190,16 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
public static byte[] edit {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("edit", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
@ -220,6 +240,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Add.
|
||||
/// </summary>
|
||||
public static string textAdd {
|
||||
get {
|
||||
return ResourceManager.GetString("textAdd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Agencies.
|
||||
/// </summary>
|
||||
@ -409,6 +438,24 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Delete.
|
||||
/// </summary>
|
||||
public static string textDelete {
|
||||
get {
|
||||
return ResourceManager.GetString("textDelete", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Deleted.
|
||||
/// </summary>
|
||||
public static string textDeleted {
|
||||
get {
|
||||
return ResourceManager.GetString("textDeleted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Departure terminal.
|
||||
/// </summary>
|
||||
@ -427,6 +474,24 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Edit.
|
||||
/// </summary>
|
||||
public static string textEdit {
|
||||
get {
|
||||
return ResourceManager.GetString("textEdit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Edit ship.
|
||||
/// </summary>
|
||||
public static string textEditShip {
|
||||
get {
|
||||
return ResourceManager.GetString("textEditShip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Edit ship call.
|
||||
/// </summary>
|
||||
@ -436,6 +501,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Edit ships.
|
||||
/// </summary>
|
||||
public static string textEditShips {
|
||||
get {
|
||||
return ResourceManager.GetString("textEditShips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Edit times.
|
||||
/// </summary>
|
||||
@ -904,6 +978,15 @@ namespace BreCalClient.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Tug company.
|
||||
/// </summary>
|
||||
public static string textTugCompany {
|
||||
get {
|
||||
return ResourceManager.GetString("textTugCompany", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Tug required.
|
||||
/// </summary>
|
||||
|
||||
@ -427,4 +427,25 @@
|
||||
<data name="textStarboard" xml:space="preserve">
|
||||
<value>Steuerbord</value>
|
||||
</data>
|
||||
<data name="textAdd" xml:space="preserve">
|
||||
<value>Hinzufügen</value>
|
||||
</data>
|
||||
<data name="textDelete" xml:space="preserve">
|
||||
<value>Löschen</value>
|
||||
</data>
|
||||
<data name="textEdit" xml:space="preserve">
|
||||
<value>Bearbeiten</value>
|
||||
</data>
|
||||
<data name="textEditShips" xml:space="preserve">
|
||||
<value>Schiffe anlegen / bearbeiten</value>
|
||||
</data>
|
||||
<data name="textDeleted" xml:space="preserve">
|
||||
<value>Gelöscht</value>
|
||||
</data>
|
||||
<data name="textEditShip" xml:space="preserve">
|
||||
<value>Schiff bearbeiten</value>
|
||||
</data>
|
||||
<data name="textTugCompany" xml:space="preserve">
|
||||
<value>Schlepper-Reederei</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -118,6 +118,9 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="add" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>add.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="arrow_down_green" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>arrow_down_green.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
@ -154,6 +157,9 @@
|
||||
<data name="delete2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>delete2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="edit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>edit.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="emergency_stop_button" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>emergency_stop_button.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
@ -166,6 +172,9 @@
|
||||
<data name="sign_warning" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>sign_warning.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="textAdd" xml:space="preserve">
|
||||
<value>Add</value>
|
||||
</data>
|
||||
<data name="textAgencies" xml:space="preserve">
|
||||
<value>Agencies</value>
|
||||
</data>
|
||||
@ -229,15 +238,30 @@
|
||||
<data name="textConfirmation" xml:space="preserve">
|
||||
<value>Confirmation</value>
|
||||
</data>
|
||||
<data name="textDelete" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="textDeleted" xml:space="preserve">
|
||||
<value>Deleted</value>
|
||||
</data>
|
||||
<data name="textDepartureTerminal" xml:space="preserve">
|
||||
<value>Departure terminal</value>
|
||||
</data>
|
||||
<data name="textDraft" xml:space="preserve">
|
||||
<value>Draft (m)</value>
|
||||
</data>
|
||||
<data name="textEdit" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="textEditShip" xml:space="preserve">
|
||||
<value>Edit ship</value>
|
||||
</data>
|
||||
<data name="textEditShipcall" xml:space="preserve">
|
||||
<value>Edit ship call</value>
|
||||
</data>
|
||||
<data name="textEditShips" xml:space="preserve">
|
||||
<value>Edit ships</value>
|
||||
</data>
|
||||
<data name="textEditTimes" xml:space="preserve">
|
||||
<value>Edit times</value>
|
||||
</data>
|
||||
@ -394,6 +418,9 @@
|
||||
<data name="textTug" xml:space="preserve">
|
||||
<value>Tug</value>
|
||||
</data>
|
||||
<data name="textTugCompany" xml:space="preserve">
|
||||
<value>Tug company</value>
|
||||
</data>
|
||||
<data name="textTugRequired" xml:space="preserve">
|
||||
<value>Tug required</value>
|
||||
</data>
|
||||
|
||||
BIN
src/BreCalClient/Resources/add.png
Normal file
BIN
src/BreCalClient/Resources/add.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/BreCalClient/Resources/edit.png
Normal file
BIN
src/BreCalClient/Resources/edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@ -100,8 +100,8 @@ namespace BreCalClient
|
||||
}
|
||||
if(sfm.Categories != null)
|
||||
{
|
||||
foreach(int category in sfm.Categories)
|
||||
this.comboBoxCategories.SelectedItems.Add((Extensions.TypeEnum)category);
|
||||
foreach(ShipcallType category in sfm.Categories)
|
||||
this.comboBoxCategories.SelectedItems.Add(category);
|
||||
}
|
||||
if (sfm.SearchString != null) this.textBoxSearch.Text = sfm.SearchString;
|
||||
this.upDownShiplengthFrom.Value = sfm.ShipLengthFrom;
|
||||
@ -124,7 +124,7 @@ namespace BreCalClient
|
||||
|
||||
private void UserControl_Loaded(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
this.comboBoxCategories.ItemsSource = Enum.GetValues(typeof(Extensions.TypeEnum));
|
||||
this.comboBoxCategories.ItemsSource = Enum.GetValues(typeof(ShipcallType));
|
||||
}
|
||||
|
||||
private void datePickerETAFrom_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
|
||||
@ -142,7 +142,7 @@ namespace BreCalClient
|
||||
private void comboBoxCategories_ItemSelectionChanged(object sender, Xceed.Wpf.Toolkit.Primitives.ItemSelectionChangedEventArgs e)
|
||||
{
|
||||
_model.Categories.Clear();
|
||||
foreach(int category in comboBoxCategories.SelectedItems)
|
||||
foreach(ShipcallType category in comboBoxCategories.SelectedItems)
|
||||
_model.Categories.Add(category);
|
||||
|
||||
SearchFilterChanged?.Invoke();
|
||||
|
||||
@ -19,7 +19,7 @@ namespace BreCalClient
|
||||
|
||||
public DateTime? EtaTo { get; set; }
|
||||
|
||||
public List<int> Categories { get; set; } = new();
|
||||
public List<ShipcallType> Categories { get; set; } = new();
|
||||
|
||||
public List<int> Agencies { get; set; } = new();
|
||||
|
||||
|
||||
41
src/BreCalClient/ShipListDialog.xaml
Normal file
41
src/BreCalClient/ShipListDialog.xaml
Normal file
@ -0,0 +1,41 @@
|
||||
<Window x:Class="BreCalClient.ShipListDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:p = "clr-namespace:BreCalClient.Resources"
|
||||
xmlns:local="clr-namespace:BreCalClient"
|
||||
mc:Ignorable="d" Left="{local:SettingBinding W1Left}" Top="{local:SettingBinding W1Top}"
|
||||
Height="490" Width="800" ResizeMode="CanResize" Icon="Resources/containership.ico" Loaded="Window_Loaded">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="28" />
|
||||
</Grid.RowDefinitions>
|
||||
<local:ENIDataGrid x:Name="dataGridShips" Grid.Row="0" SelectionMode="Single" IsReadOnly="True" AlternatingRowBackground="LightBlue" AutoGenerateColumns="False"
|
||||
CanUserAddRows="False" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
|
||||
<local:ENIDataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Ship.Deleted}" Value="True">
|
||||
<Setter Property="Foreground" Value="DarkGray"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</local:ENIDataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Id" Binding="{Binding Path=Ship.Id}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="Name" Binding="{Binding Path=Ship.Name}" IsReadOnly="True"/>
|
||||
<DataGridCheckBoxColumn Header="{x:Static p:Resources.textTug}" Binding="{Binding Path=Ship.IsTug, Mode=OneWay}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="{x:Static p:Resources.textTugCompany}" Binding="{Binding Path=TugCompany, Mode=OneWay}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="IMO" Binding="{Binding Path=Ship.Imo}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="{x:Static p:Resources.textCallsign}" Binding="{Binding Path=Ship.Callsign}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="{x:Static p:Resources.textLength}" Binding="{Binding Path=Ship.Length}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="{x:Static p:Resources.textWidth}" Binding="{Binding Path=Ship.Width}" IsReadOnly="True"/>
|
||||
<DataGridCheckBoxColumn Header="{x:Static p:Resources.textDeleted}" Binding="{Binding Path=Ship.Deleted, Mode=OneWay}" IsReadOnly="True" />
|
||||
</DataGrid.Columns>
|
||||
</local:ENIDataGrid>
|
||||
<Button Grid.Row="1" x:Name="buttonClose" Content="{x:Static p:Resources.textClose}" HorizontalAlignment="Right" Margin="2" Click="buttonClose_Click"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
116
src/BreCalClient/ShipListDialog.xaml.cs
Normal file
116
src/BreCalClient/ShipListDialog.xaml.cs
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2023 schick Informatik
|
||||
// Description: Administration screen for ships
|
||||
//
|
||||
|
||||
|
||||
using BreCalClient.misc.Api;
|
||||
using BreCalClient.misc.Model;
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace BreCalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ShipListDialog.xaml
|
||||
/// </summary>
|
||||
public partial class ShipListDialog : Window
|
||||
{
|
||||
public ShipListDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
public ShipApi? ShipApi { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handler
|
||||
|
||||
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.dataGridShips.Initialize();
|
||||
this.dataGridShips.ItemsSource = BreCalLists.AllShips;
|
||||
|
||||
this.dataGridShips.CreateRequested += DataGridShips_CreateRequested; ;
|
||||
this.dataGridShips.EditRequested += DataGridShips_EditRequested;
|
||||
this.dataGridShips.DeleteRequested += DataGridShips_DeleteRequested;
|
||||
}
|
||||
|
||||
private async void DataGridShips_DeleteRequested(object obj)
|
||||
{
|
||||
if (obj is ShipModel shipmodel)
|
||||
{
|
||||
if(this.ShipApi != null)
|
||||
await this.ShipApi.ShipDeleteAsync(shipmodel.Ship.Id);
|
||||
BreCalLists.Ships.Remove(shipmodel); // remove from "selectable" ships
|
||||
shipmodel.Ship.Deleted = true; // set deleted marker on working instance
|
||||
}
|
||||
}
|
||||
|
||||
private async void DataGridShips_EditRequested(object obj)
|
||||
{
|
||||
if (obj is ShipModel shipmodel)
|
||||
{
|
||||
EditShipDialog esd = new()
|
||||
{
|
||||
Ship = shipmodel.Ship
|
||||
};
|
||||
esd.Participants.AddRange(BreCalLists.Participants_Tug);
|
||||
|
||||
if (esd.ShowDialog() ?? false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.ShipApi != null)
|
||||
{
|
||||
Id tmpId = await this.ShipApi.ShipUpdateAsync(shipmodel.Ship);
|
||||
}
|
||||
this.dataGridShips.ItemsSource = null;
|
||||
this.dataGridShips.ItemsSource = BreCalLists.AllShips;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DataGridShips_CreateRequested()
|
||||
{
|
||||
ShipModel shipModel = new ShipModel(new Ship());
|
||||
EditShipDialog esd = new()
|
||||
{
|
||||
Ship = shipModel.Ship
|
||||
};
|
||||
esd.Participants.AddRange(BreCalLists.Participants_Tug);
|
||||
|
||||
if(esd.ShowDialog() ?? false)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.ShipApi?.ShipsCreateAsync(shipModel.Ship);
|
||||
this.dataGridShips.ItemsSource = null;
|
||||
BreCalLists.AllShips.Add(shipModel);
|
||||
BreCalLists.Ships.Add(shipModel);
|
||||
this.dataGridShips.ItemsSource = BreCalLists.AllShips;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@ -16,6 +16,16 @@ namespace BreCalClient
|
||||
|
||||
public Ship Ship { get; private set; }
|
||||
|
||||
public string TugCompany
|
||||
{
|
||||
get { if(this.Ship.ParticipantId.HasValue)
|
||||
{
|
||||
return BreCalLists.ParticipantLookupDict[this.Ship.ParticipantId.Value].Name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} ({1})", this.Ship.Name, this.Ship.Imo);
|
||||
|
||||
@ -209,13 +209,13 @@ namespace BreCalClient
|
||||
// this.labelShipName.Content = this.ShipcallControlModel?.Ship?.Name;
|
||||
switch (this.ShipcallControlModel?.Shipcall?.Type)
|
||||
{
|
||||
case 1: // incoming
|
||||
case ShipcallType.Arrival: // incoming
|
||||
this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalDevelClient;component/Resources/arrow_down_red.png"));
|
||||
break;
|
||||
case 2: // outgoing
|
||||
case ShipcallType.Departure: // outgoing
|
||||
this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalDevelClient;component/Resources/arrow_up_blue.png"));
|
||||
break;
|
||||
case 3: // shifting
|
||||
case ShipcallType.Shifting: // shifting
|
||||
this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalDevelClient;component/Resources/arrow_right_green.png"));
|
||||
break;
|
||||
default:
|
||||
@ -274,11 +274,11 @@ namespace BreCalClient
|
||||
|
||||
this.textBlockBerth.Text = this.ShipcallControlModel?.Berth;
|
||||
this.textBlockCallsign.Text = this.ShipcallControlModel?.Ship?.Callsign;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type == 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Arrival)
|
||||
{
|
||||
this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Eta?.ToString("dd.MM. HH:mm");
|
||||
}
|
||||
if ((this.ShipcallControlModel?.Shipcall?.Type == 2) || (this.ShipcallControlModel?.Shipcall?.Type == 3))
|
||||
if ((this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Departure) || (this.ShipcallControlModel?.Shipcall?.Type == ShipcallType.Shifting))
|
||||
{
|
||||
this.labelETA.Text = "ETD";
|
||||
this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Etd?.ToString("dd.MM. HH:mm");
|
||||
@ -290,7 +290,7 @@ namespace BreCalClient
|
||||
// rename labels if this is not an incoming
|
||||
// must be here because there may not be a times record for each participant (yet)
|
||||
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelETAETDAgent.Content = "ETD";
|
||||
this.labelETAETDMooring.Content = "ETD";
|
||||
@ -310,7 +310,7 @@ namespace BreCalClient
|
||||
this.labelAgencyETAETDValue.Content = agencyTimes.EtaBerth.HasValue ? agencyTimes.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
this.textBlockAgencyRemarks.Text = agencyTimes.Remarks;
|
||||
this.textBlockAgencyBerthRemarks.Text = agencyTimes.BerthInfo;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelAgencyETAETDValue.Content = agencyTimes.EtdBerth.HasValue ? agencyTimes.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
}
|
||||
@ -330,7 +330,7 @@ namespace BreCalClient
|
||||
|
||||
this.labelMooringETAETDValue.Content = mooringTimes.EtaBerth.HasValue ? mooringTimes.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
this.textBlockMooringRemarks.Text = mooringTimes.Remarks;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelMooringETAETDValue.Content = mooringTimes.EtdBerth.HasValue ? mooringTimes.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
}
|
||||
@ -346,7 +346,7 @@ namespace BreCalClient
|
||||
{
|
||||
this.labelPortAuthorityETAETDValue.Content = portAuthorityTimes.EtaBerth.HasValue ? portAuthorityTimes.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
this.textBlockPortAuthorityRemarks.Text = portAuthorityTimes.Remarks;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelPortAuthorityETAETDValue.Content = portAuthorityTimes.EtdBerth.HasValue ? portAuthorityTimes.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
}
|
||||
@ -362,7 +362,7 @@ namespace BreCalClient
|
||||
{
|
||||
this.labelPilotETAETDValue.Content = pilotTimes.EtaBerth.HasValue ? pilotTimes.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
this.textBlockPilotRemarks.Text = pilotTimes.Remarks;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelPilotETAETDValue.Content = pilotTimes.EtdBerth.HasValue ? pilotTimes.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
}
|
||||
@ -378,7 +378,7 @@ namespace BreCalClient
|
||||
{
|
||||
this.labelTugETAETDValue.Content = tugTimes.EtaBerth.HasValue ? tugTimes.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
this.textBlockTugRemarks.Text = tugTimes.Remarks;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelTugETAETDValue.Content = tugTimes.EtdBerth.HasValue ? tugTimes.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
}
|
||||
@ -395,7 +395,7 @@ namespace BreCalClient
|
||||
this.labelTerminalBerth.Content = this.ShipcallControlModel?.GetBerthText(terminalTimes);
|
||||
this.labelOperationsStart.Content = terminalTimes.OperationsStart.HasValue ? terminalTimes.OperationsStart.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
this.textBlockTerminalRemarks.Text = terminalTimes.Remarks;
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != 1)
|
||||
if (this.ShipcallControlModel?.Shipcall?.Type != ShipcallType.Arrival)
|
||||
{
|
||||
this.labelOperationsStart.Content = terminalTimes.OperationsEnd.HasValue ? terminalTimes.OperationsEnd.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
|
||||
}
|
||||
|
||||
@ -96,8 +96,7 @@ namespace BreCalClient
|
||||
get
|
||||
{
|
||||
if (this.Shipcall == null) return "";
|
||||
Extensions.TypeEnum callType = (Extensions.TypeEnum) this.Shipcall.Type;
|
||||
return string.Format("{0} {1}", callType, this.Ship?.Name);
|
||||
return string.Format("{0} {1}", this.Shipcall.Type, this.Ship?.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,15 +159,15 @@ namespace BreCalClient
|
||||
public string? GetBerthText(Times times)
|
||||
{
|
||||
string? berthText = null;
|
||||
if ((BreCalLists.AllBerths != null) && times.BerthId.HasValue && (this.Shipcall?.Type != (int)Extensions.TypeEnum.Shifting))
|
||||
if ((BreCalLists.Berths != null) && times.BerthId.HasValue && (this.Shipcall?.Type != ShipcallType.Shifting))
|
||||
{
|
||||
Berth? berth = BreCalLists.AllBerths.Find((x) => x.Id == times.BerthId);
|
||||
berthText = berth?.Name;
|
||||
}
|
||||
|
||||
if ((berthText == null) && (times.ParticipantType != (int)Extensions.ParticipantType.TERMINAL))
|
||||
if ((berthText == null) && (times.ParticipantType != (int) Extensions.ParticipantType.TERMINAL))
|
||||
{
|
||||
if (this.Shipcall?.Type == (int)Extensions.TypeEnum.Incoming)
|
||||
if (this.Shipcall?.Type == ShipcallType.Arrival)
|
||||
{
|
||||
Berth? berth = BreCalLists.AllBerths?.Find((x) => x.Id == this.Shipcall?.ArrivalBerthId);
|
||||
berthText = berth?.Name;
|
||||
@ -189,7 +188,7 @@ namespace BreCalClient
|
||||
/// This function updates the assignments for existing times records accordingly and saves them.
|
||||
/// </summary>
|
||||
/// <param name="_api">API reference to PUT eidted times</param>
|
||||
internal async void UpdateTimesAssignments(DefaultApi _api)
|
||||
internal async void UpdateTimesAssignments(TimesApi api)
|
||||
{
|
||||
foreach (Extensions.ParticipantType participantType in this.AssignedParticipants.Keys)
|
||||
{
|
||||
@ -198,7 +197,7 @@ namespace BreCalClient
|
||||
if(times.ParticipantId != this.AssignedParticipants[participantType].ParticipantId)
|
||||
{
|
||||
times.ParticipantId = this.AssignedParticipants[participantType].ParticipantId;
|
||||
await _api.TimesPutAsync(times);
|
||||
await api.TimesUpdateAsync(times);
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +224,7 @@ namespace BreCalClient
|
||||
|
||||
foreach(Times times in deleteTimes)
|
||||
{
|
||||
_api.TimesDelete(times.Id);
|
||||
api.TimesDelete(times.Id);
|
||||
this.Times.Remove(times);
|
||||
}
|
||||
}
|
||||
|
||||
31
src/BreCalClient/Util.cs
Normal file
31
src/BreCalClient/Util.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace BreCalClient
|
||||
{
|
||||
public static class Util
|
||||
{
|
||||
public static BitmapImage? LoadImage (byte[] imageData)
|
||||
{
|
||||
if (imageData == null || imageData.Length == 0) return null;
|
||||
var image = new BitmapImage();
|
||||
using (var mem = new MemoryStream(imageData))
|
||||
{
|
||||
mem.Position = 0;
|
||||
image.BeginInit();
|
||||
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
image.UriSource = null;
|
||||
image.StreamSource = mem;
|
||||
image.EndInit();
|
||||
}
|
||||
image.Freeze();
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,7 @@ from .api import berths
|
||||
from .api import ships
|
||||
from .api import login
|
||||
from .api import user
|
||||
from .api import history
|
||||
|
||||
from BreCal.brecal_utils.file_handling import get_project_root, ensure_path
|
||||
from BreCal.brecal_utils.test_handling import execute_test_with_pytest, execute_coverage_test
|
||||
@ -59,7 +60,7 @@ def create_app(test_config=None):
|
||||
app.register_blueprint(ships.bp)
|
||||
app.register_blueprint(login.bp)
|
||||
app.register_blueprint(user.bp)
|
||||
|
||||
app.register_blueprint(history.bp)
|
||||
|
||||
logging.basicConfig(filename='brecaldevel.log', level=logging.DEBUG, format='%(asctime)s | %(name)s | %(levelname)s | %(message)s')
|
||||
local_db.initPool(os.path.dirname(app.instance_path))
|
||||
|
||||
21
src/server/BreCal/api/history.py
Normal file
21
src/server/BreCal/api/history.py
Normal file
@ -0,0 +1,21 @@
|
||||
from flask import Blueprint, request
|
||||
from .. import impl
|
||||
from ..services.auth_guard import auth_guard
|
||||
import json
|
||||
|
||||
bp = Blueprint('history', __name__)
|
||||
|
||||
@bp.route('/history', methods=['get'])
|
||||
@auth_guard() # no restriction by role
|
||||
def GetParticipant():
|
||||
|
||||
if 'Authorization' in request.headers:
|
||||
token = request.headers.get('Authorization')
|
||||
options = {}
|
||||
if not 'shipcall_id' in request.args:
|
||||
return json.dumps("missing parameter"), 400
|
||||
options["shipcall_id"] = request.args.get("shipcall_id")
|
||||
return impl.history.GetHistory(options)
|
||||
else:
|
||||
return json.dumps("not authenticated"), 403
|
||||
|
||||
@ -10,12 +10,10 @@ bp = Blueprint('notifications', __name__)
|
||||
@bp.route('/notifications', methods=['get'])
|
||||
@auth_guard() # no restriction by role
|
||||
def GetNotifications():
|
||||
|
||||
if 'participant_id' in request.args:
|
||||
if 'shipcall_id' in request.args:
|
||||
options = {}
|
||||
options["participant_id"] = request.args.get("participant_id")
|
||||
options["shipcall_id"] = request.args.get("shipcall_id")
|
||||
return impl.notifications.GetNotifications(options)
|
||||
else:
|
||||
logging.warning("attempt to load notifications without participant id")
|
||||
logging.warning("attempt to load notifications without shipcall id")
|
||||
return json.dumps("missing argument"), 400
|
||||
@ -45,6 +45,7 @@ def PutShipcalls():
|
||||
|
||||
try:
|
||||
content = request.get_json(force=True)
|
||||
logging.info(content)
|
||||
loadedModel = model.ShipcallSchema().load(data=content, many=False, partial=True)
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
from flask import Blueprint, request
|
||||
from .. import impl
|
||||
from ..services.auth_guard import auth_guard
|
||||
from marshmallow import EXCLUDE
|
||||
from ..schemas import model
|
||||
import json
|
||||
import logging
|
||||
|
||||
bp = Blueprint('ships', __name__)
|
||||
|
||||
@ -14,3 +17,48 @@ def GetShips():
|
||||
return impl.ships.GetShips(token)
|
||||
else:
|
||||
return json.dumps("not authenticated"), 403
|
||||
|
||||
|
||||
@bp.route('/ships', methods=['post'])
|
||||
@auth_guard() # no restriction by role
|
||||
def PostShip():
|
||||
|
||||
try:
|
||||
content = request.get_json(force=True)
|
||||
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True)
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
return json.dumps("bad format"), 400
|
||||
|
||||
return impl.ships.PostShip(loadedModel)
|
||||
|
||||
|
||||
@bp.route('/ships', methods=['put'])
|
||||
@auth_guard() # no restriction by role
|
||||
def PutShip():
|
||||
|
||||
try:
|
||||
content = request.get_json(force=True)
|
||||
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True, unknown=EXCLUDE)
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
return json.dumps("bad format"), 400
|
||||
|
||||
return impl.ships.PutShip(loadedModel)
|
||||
|
||||
|
||||
@bp.route('/ships', methods=['delete'])
|
||||
@auth_guard() # no restriction by role
|
||||
def DeleteShip():
|
||||
|
||||
try:
|
||||
content = request.get_json(force=True)
|
||||
loadedModel = model.ShipSchema().load(data=content, many=False, partial=True, unknown=EXCLUDE)
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
return json.dumps("bad format"), 400
|
||||
|
||||
return impl.ships.DeleteShip(loadedModel)
|
||||
|
||||
@ -6,3 +6,4 @@ from . import times
|
||||
from . import ships
|
||||
from . import login
|
||||
from . import user
|
||||
from . import history
|
||||
@ -10,8 +10,6 @@ def GetBerths(token):
|
||||
No parameters, gets all entries
|
||||
"""
|
||||
|
||||
# TODO: validate token
|
||||
|
||||
try:
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
|
||||
39
src/server/BreCal/impl/history.py
Normal file
39
src/server/BreCal/impl/history.py
Normal file
@ -0,0 +1,39 @@
|
||||
import json
|
||||
import logging
|
||||
import pydapper
|
||||
import pdb
|
||||
|
||||
from ..schemas import model
|
||||
from ..schemas.model import History
|
||||
|
||||
from .. import local_db
|
||||
|
||||
def GetHistory(options):
|
||||
|
||||
"""
|
||||
:param options: A dictionary containing all the paramters for the Operations
|
||||
options["shipcall_id"]: **Id of shipcall**.
|
||||
"""
|
||||
|
||||
try:
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
|
||||
if "shipcall_id" in options and options["shipcall_id"]:
|
||||
data = commands.query("SELECT id, participant_id, shipcall_id, timestamp, eta, type, operation FROM history WHERE shipcall_id = ?shipcallid?",
|
||||
model=History.from_query_row,
|
||||
param={"shipcallid" : options["shipcall_id"]})
|
||||
|
||||
|
||||
pooledConnection.close()
|
||||
|
||||
except Exception as ex:
|
||||
pdb.pm()
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
return json.dumps("call failed"), 500
|
||||
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
@ -14,7 +14,9 @@ def GetUser(options):
|
||||
hash = bcrypt.hashpw(options["password"].encode('utf-8'), bcrypt.gensalt( 12 )).decode('utf8')
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
data = commands.query("SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, api_key, created, modified FROM user WHERE user_name = ?username? OR user_email = ?username?",
|
||||
data = commands.query("SELECT id, participant_id, first_name, last_name, user_name, user_email, user_phone, password_hash, " +
|
||||
"api_key, notify_email, notify_whatsapp, notify_signal, notify_popup, created, modified FROM user " +
|
||||
"WHERE user_name = ?username? OR user_email = ?username?",
|
||||
model=model.User, param={"username" : options["username"]})
|
||||
# print(data)
|
||||
if len(data) == 1:
|
||||
|
||||
@ -8,22 +8,25 @@ from .. import local_db
|
||||
def GetNotifications(options):
|
||||
"""
|
||||
:param options: A dictionary containing all the paramters for the Operations
|
||||
options["participant_id"]: **Id of participant**. *Example: 2*. Id returned through loading of participant
|
||||
options["shipcall_id"]: **Id of ship call**. *Example: 52*. Id given in ship call list
|
||||
options["shipcall_id"]: **Id**. *Example: 42*. Id of referenced ship call.
|
||||
|
||||
"""
|
||||
|
||||
# Implement your business logic here
|
||||
# All the parameters are present in the options argument
|
||||
|
||||
return json.dumps({
|
||||
"acknowledged": "<boolean>",
|
||||
"id": "<integer>",
|
||||
"notification_type": "<string>",
|
||||
"participant_id": "<integer>",
|
||||
"times_id": "<integer>",
|
||||
"timestamp": "<date-time>",
|
||||
}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
try:
|
||||
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
data = commands.query("SELECT id, shipcall_id, level, type, message, created, modified FROM notification " +
|
||||
"WHERE shipcall_id = ?scid?", model=model.Notification.from_query_row, param={"scid" : options["shipcall_id"]})
|
||||
pooledConnection.close()
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
return json.dumps(data, default=model.obj_dict), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import pydapper
|
||||
|
||||
from ..schemas import model
|
||||
from .. import local_db
|
||||
from ..services.auth_guard import check_jwt
|
||||
|
||||
from BreCal.database.update_database import evaluate_shipcall_state
|
||||
|
||||
@ -20,7 +21,7 @@ def GetShipcalls(options):
|
||||
query = ("SELECT s.id as id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
|
||||
"flags, s.pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, " +
|
||||
"tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, " +
|
||||
"evaluation_message, s.created as created, s.modified as modified " +
|
||||
"evaluation_message, evaluation_time, evaluation_notifications_sent, s.created as created, s.modified as modified " +
|
||||
"FROM shipcall s " +
|
||||
"LEFT JOIN times t ON t.shipcall_id = s.id AND t.participant_type = 8 " +
|
||||
"WHERE " +
|
||||
@ -32,7 +33,7 @@ def GetShipcalls(options):
|
||||
"(etd >= DATE(NOW() - INTERVAL %d DAY)))) " +
|
||||
"ORDER BY eta") % (options["past_days"], options["past_days"], options["past_days"], options["past_days"])
|
||||
|
||||
data = commands.query(query, model=model.Shipcall)
|
||||
data = commands.query(query, model=model.Shipcall.from_query_row, buffered=True)
|
||||
for shipcall in data:
|
||||
participant_query = "SELECT participant_id, type FROM shipcall_participant_map WHERE shipcall_id=?shipcall_id?";
|
||||
for record in commands.query(participant_query, model=dict, param={"shipcall_id" : shipcall.id}, buffered=False):
|
||||
@ -112,13 +113,20 @@ def PostShipcalls(schemaModel):
|
||||
commands.execute(query, schemaModel)
|
||||
new_id = commands.execute_scalar("select last_insert_id()")
|
||||
|
||||
# add participant assignments
|
||||
# add participant assignments if we have a list of participants
|
||||
if 'participants' in schemaModel:
|
||||
pquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
|
||||
for participant_assignment in schemaModel["participants"]:
|
||||
commands.execute(pquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
|
||||
|
||||
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
|
||||
evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id
|
||||
# evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id
|
||||
|
||||
# save history data
|
||||
# TODO: set ETA properly
|
||||
user_data = check_jwt()
|
||||
query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 1)"
|
||||
commands.execute(query, {"scid" : new_id, "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||
|
||||
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
@ -205,6 +213,13 @@ def PutShipcalls(schemaModel):
|
||||
commands.execute(dquery, param={"existing_id" : elem["id"]})
|
||||
|
||||
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
|
||||
# evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["id"]) # schemaModel["id"] refers to the shipcall id
|
||||
|
||||
# save history data
|
||||
# TODO: set ETA properly
|
||||
user_data = check_jwt()
|
||||
query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 2)"
|
||||
commands.execute(query, {"scid" : schemaModel["id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||
|
||||
return json.dumps({"id" : schemaModel["id"]}), 200
|
||||
|
||||
|
||||
@ -10,8 +10,6 @@ def GetShips(token):
|
||||
No parameters, gets all entries
|
||||
"""
|
||||
|
||||
# TODO: validate token
|
||||
|
||||
try:
|
||||
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
@ -35,3 +33,127 @@ def GetShips(token):
|
||||
|
||||
|
||||
|
||||
def PostShip(schemaModel):
|
||||
"""
|
||||
:param schemaModel: The deserialized model of the record to be inserted
|
||||
"""
|
||||
|
||||
# TODO: Validate the incoming data
|
||||
|
||||
# This creates a *new* entry
|
||||
try:
|
||||
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
|
||||
query = "INSERT INTO ship ("
|
||||
isNotFirst = False
|
||||
for key in schemaModel.keys():
|
||||
if key == "id":
|
||||
continue
|
||||
if key == "created":
|
||||
continue
|
||||
if key == "modified":
|
||||
continue
|
||||
if isNotFirst:
|
||||
query += ","
|
||||
isNotFirst = True
|
||||
query += key
|
||||
query += ") VALUES ("
|
||||
isNotFirst = False
|
||||
for key in schemaModel.keys():
|
||||
if key == "id":
|
||||
continue
|
||||
if key == "created":
|
||||
continue
|
||||
if key == "modified":
|
||||
continue
|
||||
if isNotFirst:
|
||||
query += ","
|
||||
isNotFirst = True
|
||||
query += "?" + key + "?"
|
||||
query += ")"
|
||||
|
||||
commands.execute(query, schemaModel)
|
||||
new_id = commands.execute_scalar("select last_insert_id()")
|
||||
|
||||
pooledConnection.close()
|
||||
|
||||
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
def PutShip(schemaModel):
|
||||
"""
|
||||
:param schemaModel: The deserialized model of the record to be inserted
|
||||
"""
|
||||
|
||||
# This updates an *existing* entry
|
||||
try:
|
||||
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
|
||||
query = "UPDATE ship SET "
|
||||
isNotFirst = False
|
||||
for key in schemaModel.keys():
|
||||
if key == "id":
|
||||
continue
|
||||
if key == "created":
|
||||
continue
|
||||
if key == "modified":
|
||||
continue
|
||||
if isNotFirst:
|
||||
query += ", "
|
||||
isNotFirst = True
|
||||
query += key + " = ?" + key + "? "
|
||||
|
||||
query += "WHERE id = ?id?"
|
||||
|
||||
affected_rows = commands.execute(query, param=schemaModel)
|
||||
|
||||
pooledConnection.close()
|
||||
|
||||
return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
def DeleteShip(options):
|
||||
"""
|
||||
:param options: A dictionary containing all the paramters for the Operations
|
||||
options["id"]
|
||||
|
||||
"""
|
||||
try:
|
||||
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
commands = pydapper.using(pooledConnection)
|
||||
affected_rows = commands.execute("UPDATE ship SET deleted = 1 WHERE id = ?id?", param={"id" : options["id"]})
|
||||
|
||||
pooledConnection.close()
|
||||
|
||||
if affected_rows == 1:
|
||||
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
result = {}
|
||||
result["message"] = "no such record"
|
||||
return json.dumps(result), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
result["message"] = "call failed"
|
||||
return json.dumps(result), 500, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
@ -1,9 +1,11 @@
|
||||
import json
|
||||
import logging
|
||||
import traceback
|
||||
import pydapper
|
||||
|
||||
from ..schemas import model
|
||||
from .. import local_db
|
||||
from ..services.auth_guard import check_jwt
|
||||
|
||||
from BreCal.database.update_database import evaluate_shipcall_state
|
||||
|
||||
@ -14,8 +16,6 @@ def GetTimes(options):
|
||||
|
||||
"""
|
||||
|
||||
# TODO: validate token
|
||||
|
||||
try:
|
||||
|
||||
pooledConnection = local_db.getPoolConnection()
|
||||
@ -27,6 +27,7 @@ def GetTimes(options):
|
||||
pooledConnection.close()
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(traceback.format_exc())
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
@ -85,9 +86,16 @@ def PostTimes(schemaModel):
|
||||
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall'
|
||||
evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id'
|
||||
|
||||
# save history data
|
||||
# TODO: set ETA properly
|
||||
user_data = check_jwt()
|
||||
query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 2, 1)"
|
||||
commands.execute(query, {"scid" : schemaModel["shipcall_id"], "pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||
|
||||
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(traceback.format_exc())
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
@ -132,13 +140,21 @@ def PutTimes(schemaModel):
|
||||
# apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall'
|
||||
evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id'
|
||||
|
||||
# save history data
|
||||
# TODO: set ETA properly
|
||||
user_data = check_jwt()
|
||||
if "participant_id" in user_data and "id" in user_data:
|
||||
query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, ?scid?, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 2, 2)"
|
||||
commands.execute(query, {"pid" : user_data["participant_id"], "scid" : schemaModel["shipcall_id"], "uid" : user_data["id"]})
|
||||
else:
|
||||
logging.error("user_data does not contain participant_id or id")
|
||||
|
||||
# if affected_rows == 1: # this doesn't work as expected
|
||||
|
||||
return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
# return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(traceback.format_exc())
|
||||
logging.error(ex)
|
||||
print(ex)
|
||||
result = {}
|
||||
@ -161,6 +177,14 @@ def DeleteTimes(options):
|
||||
commands = pydapper.using(pooledConnection)
|
||||
affected_rows = commands.execute("DELETE FROM times WHERE id = ?id?", param={"id" : options["id"]})
|
||||
|
||||
# TODO: howto get the shipcall id here? we will need to load the object first
|
||||
# TODO: set ETA properly
|
||||
|
||||
# save history data
|
||||
user_data = check_jwt()
|
||||
query = "INSERT INTO history (participant_id, shipcall_id, user_id, timestamp, eta, type, operation) VALUES (?pid?, 0, ?uid?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 2, 3)"
|
||||
commands.execute(query, {"pid" : user_data["participant_id"], "uid" : user_data["id"]})
|
||||
|
||||
if affected_rows == 1:
|
||||
return json.dumps({"id" : options["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
from dataclasses import field
|
||||
from dataclasses import field, dataclass
|
||||
from marshmallow import Schema, fields, INCLUDE, ValidationError
|
||||
from marshmallow.fields import Field
|
||||
from marshmallow_enum import EnumField
|
||||
from enum import IntEnum
|
||||
|
||||
from marshmallow_dataclass import dataclass
|
||||
from typing import List
|
||||
@ -10,6 +13,8 @@ import datetime
|
||||
def obj_dict(obj):
|
||||
if isinstance(obj, datetime.datetime):
|
||||
return obj.isoformat()
|
||||
if hasattr(obj, 'to_json'):
|
||||
return obj.to_json()
|
||||
return obj.__dict__
|
||||
|
||||
@dataclass
|
||||
@ -23,6 +28,70 @@ class Berth(Schema):
|
||||
modified: datetime
|
||||
deleted: bool
|
||||
|
||||
class OperationType(IntEnum):
|
||||
undefined = 0
|
||||
insert = 1
|
||||
update = 2
|
||||
delete = 3
|
||||
|
||||
class ObjectType(IntEnum):
|
||||
undefined = 0
|
||||
shipcall = 1
|
||||
times = 2
|
||||
|
||||
class EvaluationType(IntEnum):
|
||||
undefined = 0
|
||||
green = 1
|
||||
yellow = 2
|
||||
red = 3
|
||||
|
||||
class NotificationType(IntEnum):
|
||||
undefined = 0
|
||||
email = 1
|
||||
push = 2
|
||||
|
||||
class ShipcallType(IntEnum):
|
||||
undefined = 0
|
||||
arrival = 1
|
||||
departure = 2
|
||||
shifting = 3
|
||||
|
||||
|
||||
@dataclass
|
||||
class History:
|
||||
def __init__(self, id, participant_id, shipcall_id, timestamp, eta, type, operation):
|
||||
self.id = id
|
||||
self.participant_id = participant_id
|
||||
self.shipcall_id = shipcall_id
|
||||
self.timestamp = timestamp
|
||||
self.eta = eta
|
||||
self.type = type
|
||||
self.operation = operation
|
||||
pass
|
||||
|
||||
id: int
|
||||
participant_id: int
|
||||
shipcall_id: int
|
||||
timestamp: datetime
|
||||
eta: datetime
|
||||
type: ObjectType
|
||||
operation: OperationType
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"participant_id": self.participant_id,
|
||||
"shipcall_id": self.shipcall_id,
|
||||
"timestamp": self.timestamp.isoformat() if self.timestamp else "",
|
||||
"eta": self.eta.isoformat() if self.eta else "",
|
||||
"type": self.type.name,
|
||||
"operation": self.operation.name
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_query_row(self, id, participant_id, shipcall_id, timestamp, eta, type, operation):
|
||||
return self(id, participant_id, shipcall_id, timestamp, eta, ObjectType(type), OperationType(operation))
|
||||
|
||||
class Error(Schema):
|
||||
message = fields.String(required=True)
|
||||
|
||||
@ -31,17 +100,30 @@ class GetVerifyInlineResp(Schema):
|
||||
pass
|
||||
|
||||
@dataclass
|
||||
class Notification(Schema):
|
||||
|
||||
class Notification:
|
||||
id: int
|
||||
times_id: int
|
||||
acknowledged: bool
|
||||
shipcall_id: int
|
||||
level: int
|
||||
type: int
|
||||
type: NotificationType
|
||||
message: str
|
||||
created: datetime
|
||||
modified: datetime
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"shipcall_id": self.shipcall_id,
|
||||
"level": self.level,
|
||||
"type": self.type.name,
|
||||
"message": self.message,
|
||||
"created": self.created.isoformat() if self.created else "",
|
||||
"modified": self.modified.isoformat() if self.modified else ""
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_query_row(self, id, shipcall_id, level, type, message, created, modified):
|
||||
return self(id, shipcall_id, level, NotificationType(type), message, created, modified)
|
||||
|
||||
@dataclass
|
||||
class Participant(Schema):
|
||||
id: int
|
||||
@ -69,7 +151,7 @@ class ShipcallSchema(Schema):
|
||||
|
||||
id = fields.Int()
|
||||
ship_id = fields.Int()
|
||||
type = fields.Int()
|
||||
type = EnumField(ShipcallType, by_value=True, required=True)
|
||||
eta = fields.DateTime(Required = False, allow_none=True)
|
||||
voyage = fields.Str(allow_none=True, metadata={'Required':False}) # Solving: RemovedInMarshmallow4Warning: Passing field metadata as keyword arguments is deprecated. Use the explicit `metadata=...` argument instead. Additional metadata: {'Required': False}
|
||||
etd = fields.DateTime(Required = False, allow_none=True)
|
||||
@ -90,8 +172,10 @@ class ShipcallSchema(Schema):
|
||||
anchored = fields.Bool(Required = False, allow_none=True)
|
||||
moored_lock = fields.Bool(Required = False, allow_none=True)
|
||||
canceled = fields.Bool(Required = False, allow_none=True)
|
||||
evaluation = fields.Int(Required = False, allow_none=True)
|
||||
evaluation = EnumField(EvaluationType, required=False, allow_none=True, by_value=True)
|
||||
evaluation_message = fields.Str(allow_none=True, metadata={'Required':False}) # Solving: RemovedInMarshmallow4Warning: Passing field metadata as keyword arguments is deprecated. Use the explicit `metadata=...` argument instead. Additional metadata: {'Required': False}
|
||||
evaluation_time = fields.DateTime(Required = False, allow_none=True)
|
||||
evaluation_notifications_sent = fields.Bool(Required = False, allow_none=True)
|
||||
participants = fields.List(fields.Nested(ParticipantAssignmentSchema))
|
||||
created = fields.DateTime(Required = False, allow_none=True)
|
||||
modified = fields.DateTime(Required = False, allow_none=True)
|
||||
@ -104,14 +188,15 @@ class Participant_Assignment:
|
||||
pass
|
||||
|
||||
participant_id: int
|
||||
type: int
|
||||
type: int # a variant would be to use the IntFlag type (with appropriate serialization)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Shipcall:
|
||||
|
||||
id: int
|
||||
ship_id: int
|
||||
type: str
|
||||
type: ShipcallType
|
||||
eta: datetime
|
||||
voyage: str
|
||||
etd: datetime
|
||||
@ -132,12 +217,54 @@ class Shipcall:
|
||||
anchored: bool
|
||||
moored_lock: bool
|
||||
canceled: bool
|
||||
evaluation: int
|
||||
evaluation: EvaluationType
|
||||
evaluation_message: str
|
||||
evaluation_time: datetime
|
||||
evaluation_notifications_sent: bool
|
||||
created: datetime
|
||||
modified: datetime
|
||||
participants: List[Participant_Assignment] = field(default_factory=list)
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"ship_id": self.ship_id,
|
||||
"type": self.type.name,
|
||||
"eta": self.eta.isoformat() if self.eta else "",
|
||||
"voyage": self.voyage,
|
||||
"etd": self.etd.isoformat() if self.etd else "",
|
||||
"arrival_berth_id": self.arrival_berth_id,
|
||||
"departure_berth_id": self.departure_berth_id,
|
||||
"tug_required": self.tug_required,
|
||||
"pilot_required": self.pilot_required,
|
||||
"flags": self.flags,
|
||||
"pier_side": self.pier_side,
|
||||
"bunkering": self.bunkering,
|
||||
"replenishing_terminal": self.replenishing_terminal,
|
||||
"replenishing_lock": self.replenishing_lock,
|
||||
"draft": self.draft,
|
||||
"tidal_window_from": self.tidal_window_from.isoformat() if self.tidal_window_from else "",
|
||||
"tidal_window_to": self.tidal_window_to.isoformat() if self.tidal_window_to else "",
|
||||
"rain_sensitive_cargo": self.rain_sensitive_cargo,
|
||||
"recommended_tugs": self.recommended_tugs,
|
||||
"anchored": self.anchored,
|
||||
"moored_lock": self.moored_lock,
|
||||
"canceled": self.canceled,
|
||||
"evaluation": self.evaluation.name,
|
||||
"evaluation_message": self.evaluation_message,
|
||||
"evaluation_time": self.evaluation_time.isoformat() if self.evaluation_time else "",
|
||||
"evaluation_notifications_sent": self.evaluation_notifications_sent,
|
||||
"created": self.created.isoformat() if self.created else "",
|
||||
"modified": self.modified.isoformat() if self.modified else "",
|
||||
"participants": [participant.__dict__ for participant in self.participants]
|
||||
|
||||
}
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_query_row(self, id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, evaluation, evaluation_message, evaluation_time, evaluation_notifications_sent, created, modified):
|
||||
return self(id, ship_id, ShipcallType(type), eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, anchored, moored_lock, canceled, EvaluationType(evaluation), evaluation_message, evaluation_time, evaluation_notifications_sent, created, modified)
|
||||
|
||||
class ShipcallId(Schema):
|
||||
pass
|
||||
|
||||
@ -185,7 +312,6 @@ class UserSchema(Schema):
|
||||
|
||||
@dataclass
|
||||
class Times:
|
||||
|
||||
id: int
|
||||
eta_berth: datetime
|
||||
eta_berth_fixed: bool
|
||||
@ -219,11 +345,15 @@ class User:
|
||||
user_phone: str
|
||||
password_hash: str
|
||||
api_key: str
|
||||
notify_email: bool
|
||||
notify_whatsapp: bool
|
||||
notify_signal: bool
|
||||
notify_popup: bool
|
||||
created: datetime
|
||||
modified: datetime
|
||||
|
||||
@dataclass
|
||||
class Ship(Schema):
|
||||
class Ship:
|
||||
id: int
|
||||
name: str
|
||||
imo: int
|
||||
@ -233,11 +363,32 @@ class Ship(Schema):
|
||||
width: float
|
||||
is_tug: bool
|
||||
bollard_pull: int
|
||||
eni: str
|
||||
eni: int
|
||||
created: datetime
|
||||
modified: datetime
|
||||
deleted: bool
|
||||
|
||||
|
||||
class ShipSchema(Schema):
|
||||
def __init__(self):
|
||||
super().__init__(unknown=None)
|
||||
pass
|
||||
|
||||
id = fields.Int(Required=False)
|
||||
name = fields.String(allow_none=False, metadata={'Required':True})
|
||||
imo = fields.Int(allow_none=False, metadata={'Required':True})
|
||||
callsign = fields.String(allow_none=True, metadata={'Required':False})
|
||||
participant_id = fields.Int(allow_none=True, metadata={'Required':False})
|
||||
length = fields.Float(allow_none=True, metadata={'Required':False})
|
||||
width = fields.Float(allow_none=True, metadata={'Required':False})
|
||||
is_tug = fields.Bool(allow_none=True, metadata={'Required':False}, default=False)
|
||||
bollard_pull = fields.Int(allow_none=True, metadata={'Required':False})
|
||||
eni = fields.Int(allow_none=True, metadata={'Required':False})
|
||||
created = fields.DateTime(allow_none=True, metadata={'Required':False})
|
||||
modified = fields.DateTime(allow_none=True, metadata={'Required':False})
|
||||
deleted = fields.Bool(allow_none=True, metadata={'Required':False}, default=False)
|
||||
|
||||
|
||||
class TimesId(Schema):
|
||||
pass
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ def UpdateShipcalls(options:dict = {'past_days':2}):
|
||||
commands = pydapper.using(pooledConnection)
|
||||
query = ("SELECT id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, "
|
||||
"flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, "
|
||||
"anchored, moored_lock, canceled, evaluation, evaluation_message, created, modified FROM shipcall WHERE ((type = 1 OR type = 3) AND eta >= DATE(NOW() - INTERVAL %d DAY)"
|
||||
"anchored, moored_lock, canceled, evaluation, evaluation_message, evaluation_notifications_sent, evaluation_time, created, modified FROM shipcall WHERE ((type = 1 OR type = 3) AND eta >= DATE(NOW() - INTERVAL %d DAY)"
|
||||
"OR (type = 2 AND etd >= DATE(NOW() - INTERVAL %d DAY))) "
|
||||
"ORDER BY eta") % (options["past_days"], options["past_days"])
|
||||
|
||||
|
||||
@ -41,6 +41,8 @@ def get_shipcall_simple():
|
||||
canceled = False
|
||||
evaluation = None
|
||||
evaluation_message = ""
|
||||
evaluation_time = None
|
||||
evaluation_notifications_sent = False
|
||||
created = datetime.datetime.now()
|
||||
modified = created+datetime.timedelta(seconds=10)
|
||||
|
||||
@ -72,6 +74,8 @@ def get_shipcall_simple():
|
||||
canceled,
|
||||
evaluation,
|
||||
evaluation_message,
|
||||
evaluation_time,
|
||||
evaluation_notifications_sent,
|
||||
created,
|
||||
modified,
|
||||
participants,
|
||||
|
||||
Reference in New Issue
Block a user