Flights now sortable.

This commit is contained in:
PeekabooSteam 2023-04-16 23:34:00 +01:00
parent 3eefe441b4
commit d77735581a
7 changed files with 276 additions and 48 deletions

View File

@ -42,7 +42,7 @@
text-align: center;
}
.ol-strip-board-headers > *, .ol-strip-board-strip > * {
.ol-strip-board-headers > *, .ol-strip-board-strip > [data-point] {
padding: 4px;
text-overflow: ellipsis;
white-space: nowrap;
@ -67,19 +67,33 @@
border:1px solid #cc0000;
}
[data-board-type="ground"] .ol-strip-board-headers :nth-child(1),
[data-board-type="ground"] .ol-strip-board-headers :nth-child(2),
[data-board-type="ground"] .ol-strip-board-strip :nth-child(1),
[data-board-type="ground"] .ol-strip-board-strip :nth-child(2) {
width:120px;
.ol-strip-board-headers :nth-child(1) {
width:12px;
}
[data-board-type="ground"] .ol-strip-board-strip :nth-child(4) {
.ol-strip-board-headers :nth-child(2),
.ol-strip-board-strip :nth-child(2),
[data-board-type="ground"] .ol-strip-board-headers :nth-child(3),
[data-board-type="ground"] .ol-strip-board-strip :nth-child(3) {
width:130px;
}
[data-board-type="ground"] .ol-strip-board-strip :nth-child(5) {
text-align: center;
}
.ol-strip-board-headers :nth-child(6),
.ol-strip-board-strip :nth-child(6) {
width:20px;
}
[data-board-type="tower"] .ol-strip-board-strip > * {
text-align: center;
}
@ -88,11 +102,11 @@
text-align: left;
}
[data-board-type="tower"] .ol-strip-board-strip :nth-child(2) input {
[data-board-type="tower"] .ol-strip-board-strip :nth-child(3) input {
width:25px;
}
[data-board-type="tower"] .ol-strip-board-strip :nth-child(2) {
[data-board-type="tower"] .ol-strip-board-strip :nth-child(3) {
font-size:10px;
}
@ -112,6 +126,7 @@
.ol-strip-board-add-flight {
display:flex;
flex-flow: row nowrap;
position:relative;
}
@ -126,24 +141,36 @@
height: 12px;
}
.ol-strip-board-add-flight button[type="submit"] {
background-color: darkgreen;
border-bottom-right-radius: var( --border-radius-sm );
border-bottom-left-radius: 0;
border-top-left-radius: 0;
border-top-right-radius: var( --border-radius-sm );
.ol-strip-board-add-flight input {
border-radius: var( --border-radius-sm );
}
.ol-strip-board-add-flight input {
border-bottom-left-radius: var( --border-radius-sm );
border-top-left-radius: var( --border-radius-sm );
.ol-strip-board-add-flight .ol-auto-suggest {
background:white;
border-radius: var(--border-radius-sm );
color:black;
display:none;
flex-direction: column;
left:0;
margin:0;
position:absolute;
translate:0 -100%;
top:0;
}
.ol-strip-board-add-flight .ol-auto-suggest[data-has-suggestions] {
display:flex;
}
.ol-strip-board-add-flight .ol-auto-suggest[data-has-suggestions] a {
cursor: pointer;
}
[data-board-type="ground"] {
translate: 0 100%;
bottom:20px;
}
[data-board-type="tower"] {
translate: 0 -100%;
top:100px;
}

View File

@ -149,7 +149,7 @@ form > div {
.ol-select.narrow:not(.ol-select-image)>.ol-select-value {
opacity: .9;
padding:6px 30px 6px 15px;
padding:4px 30px 4px 15px;
}
.ol-select:not(.ol-select-image)>.ol-select-value svg {
@ -534,6 +534,15 @@ nav.ol-panel> :last-child {
}
.ol-sortable .handle {
background-image: url( "/images/icons/grip-lines-solid.svg" );
cursor:ns-resize;
filter:invert();
height:12px;
width:12px;
}
#unit-selection {
display: flex;

View File

@ -46,6 +46,15 @@ Flight.prototype.getData = function() {
}
Flight.prototype.setOrder = function( order ) {
this.order = order;
return true;
}
Flight.prototype.setStatus = function( status ) {
if ( [ "unknown", "checkedin", "readytotaxi", "clearedtotaxi", "halted", "terminated" ].indexOf( status ) < 0 ) {
@ -172,6 +181,27 @@ app.patch( "/flight/:flightId", ( req, res ) => {
});
app.post( "/flight/order", ( req, res ) => {
if ( !req.body.boardId ) {
res.status( 400 ).send( "Invalid/missing boardId" );
}
if ( !req.body.order || !Array.isArray( req.body.order ) ) {
res.status( 400 ).send( "Invalid/missing boardId" );
}
req.body.order.forEach( ( flightId, i ) => {
dataHandler.getFlight( flightId ).setOrder( i );
});
res.send( "" );
});
app.post( "/flight", ( req, res ) => {
if ( !req.body.boardId ) {

View File

@ -6,6 +6,7 @@ export interface FlightInterface {
id : string;
boardId : string;
name : string;
order : number;
status : "unknown";
takeoffTime : number;
unitId : number;

View File

@ -2,6 +2,9 @@ import { Dropdown } from "../controls/dropdown";
import { zeroAppend } from "../other/utils";
import { ATC } from "./atc";
import { Unit } from "../units/unit";
import { getUnitsManager } from "..";
import Sortable from "sortablejs";
import { FlightInterface } from "./atc";
export interface StripBoardStripInterface {
"id": string,
@ -43,6 +46,30 @@ export abstract class ATCBoard {
this.#clockElement = <HTMLElement>this.getBoardElement().querySelector( ".ol-strip-board-clock" );
new Sortable( this.getStripBoardElement(), {
"handle": ".handle",
"onUpdate": ev => {
const order = [].slice.call( this.getStripBoardElement().children ).map( ( strip:HTMLElement ) => {
return strip.dataset.flightId
});
fetch( '/api/atc/flight/order', {
method: 'POST',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId" : this.getBoardId(),
"order" : order
})
});
}
});
setInterval( () => {
this.updateClock();
}, 1000 );
@ -63,6 +90,8 @@ export abstract class ATCBoard {
this.#setupAddFlight();
//this.#_setupDemoData();
}
@ -177,7 +206,10 @@ export abstract class ATCBoard {
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
}
},
"body": JSON.stringify({
"boardId": this.getBoardId()
})
});
}
@ -220,6 +252,13 @@ export abstract class ATCBoard {
}
getUnitIdsBeingMonitored() {
return this.#unitIdsBeingMonitored;
}
setTemplates( templates:{[key:string]: string} ) {
this.#templates = templates;
}
@ -246,39 +285,82 @@ export abstract class ATCBoard {
});
this.getBoardElement().querySelectorAll( "form.ol-strip-board-add-flight" ).forEach( form => {
const form = <HTMLElement>this.getBoardElement().querySelector( "form.ol-strip-board-add-flight" );
const suggestions = <HTMLElement>form.querySelector( ".ol-auto-suggest" );
const unitName = <HTMLInputElement>form.querySelector( "input[name='unitName']" );
if ( form instanceof HTMLFormElement ) {
const toggleSuggestions = ( bool:boolean ) => {
suggestions.toggleAttribute( "data-has-suggestions", bool );
}
form.addEventListener( "submit", ev => {
let searchTimeout:number|null;
unitName.addEventListener( "keyup", ev => {
if ( searchTimeout ) {
clearTimeout( searchTimeout );
}
const resetSuggestions = () => {
suggestions.innerHTML = "";
toggleSuggestions( false );
}
resetSuggestions();
searchTimeout = setTimeout( () => {
const searchString = unitName.value.toLowerCase();
if ( searchString === "" ) {
return;
}
const units = getUnitsManager().getSelectableAircraft();
const unitIdsBeingMonitored = this.getUnitIdsBeingMonitored();
const results = Object.keys( units ).reduce( ( acc:Unit[], unitId:any ) => {
ev.preventDefault();
if ( ev.target instanceof HTMLFormElement ) {
const elements = ev.target.elements;
const flightName = <HTMLInputElement>elements[1];
if ( flightName.value === "" ) {
return;
}
// this.addFlight( -1, flightName.value );
form.reset();
const unit = units[ unitId ];
const baseData = unit.getBaseData();
if ( !unitIdsBeingMonitored.includes( parseInt( unitId ) ) && baseData.unitName.toLowerCase().indexOf( searchString ) > -1 ) {
acc.push( unit );
}
return acc;
}, [] );
toggleSuggestions( results.length > 0 );
results.forEach( unit => {
const baseData = unit.getBaseData();
const a = document.createElement( "a" );
a.innerText = baseData.unitName;
a.addEventListener( "click", ev => {
this.addFlight( unit );
resetSuggestions();
unitName.value = "";
});
suggestions.appendChild( a );
});
}
}, 1000 );
});
this.getBoardElement().querySelectorAll( ".add-flight-by-click" ).forEach( el => {
el.addEventListener( "click", () => {
form.querySelectorAll( ".add-flight-by-click" ).forEach( el => {
el.addEventListener( "click", ev => {
ev.preventDefault();
toggleIsAddFlightByClickEnabled();
});
});
@ -286,6 +368,22 @@ export abstract class ATCBoard {
}
sortFlights( flights:FlightInterface[] ) {
flights.sort( ( a, b ) => {
const aVal = a.order;
const bVal = b.order;
return ( aVal > bVal ) ? 1 : -1;
});
return flights;
}
startUpdates() {
this.#updateInterval = setInterval( () => {
@ -332,5 +430,49 @@ export abstract class ATCBoard {
}
#_setupDemoData() {
fetch( '/api/atc/flight/', {
method: 'POST',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId" : this.getBoardId(),
"name" : this.getBoardId() + " 1",
"unitId" : 1
})
});
fetch( '/api/atc/flight/', {
method: 'POST',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId" : this.getBoardId(),
"name" : this.getBoardId() + " 2",
"unitId" : 1
})
});
fetch( '/api/atc/flight/', {
method: 'POST',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId" : this.getBoardId(),
"name" : this.getBoardId() + " 3",
"unitId" : 1
})
});
}
}

View File

@ -14,7 +14,7 @@ export class ATCBoardGround extends ATCBoard {
update() {
const flights = Object.values( this.getATC().getDataHandler().getFlights( this.getBoardId() ) );
const flights = this.sortFlights( Object.values( this.getATC().getDataHandler().getFlights( this.getBoardId() ) ) );
const stripBoard = this.getStripBoardElement();
const missionTime = this.getATC().getMissionDateTime().getTime();
@ -31,6 +31,7 @@ export class ATCBoardGround extends ATCBoard {
if ( !strip ) {
const template = `<div class="ol-strip-board-strip" data-flight-id="${flight.id}" data-flight-status="${flight.status}">
<div class="handle"></div>
<div data-point="name">${flight.name}</div>
<div id="flight-status-${flight.id}" class="ol-select narrow" data-point="status">
@ -42,7 +43,7 @@ export class ATCBoardGround extends ATCBoard {
<div data-point="timeToGo">${this.timeToGo( flight.takeoffTime )}</div>
<button class="deleteFlight">Delete</button>
<button class="deleteFlight">&times;</button>
</div>`;
stripBoard.insertAdjacentHTML( "beforeend", template );

View File

@ -23,6 +23,24 @@ export class UnitsManager {
document.addEventListener('deleteSelectedUnits', () => this.selectedUnitsDelete() )
}
getSelectableAircraft() {
const units = this.getUnits();
return Object.keys( units ).reduce( ( acc:{[key:number]: Unit}, unitId:any ) => {
const baseData = units[ unitId ].getBaseData();
if ( baseData.category === "Aircraft" && baseData.alive === true ) {
acc[ unitId ] = units[ unitId ];
}
return acc;
}, {});
}
getUnits() {
return this.#units;
}