mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-19 20:25:31 +00:00
Merge branch 'bug2842'
Change-Id: I169cca2e4dfa1b65a6237ab499f4bfa21dbf15c7
This commit is contained in:
+9
-1
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.security.SecuredDomainType;
|
||||
@@ -38,18 +39,25 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
|
||||
private String regattaName;
|
||||
public String boatClass;
|
||||
|
||||
private RankingMetrics rankingMetricType;
|
||||
|
||||
public RaceDTO() {}
|
||||
|
||||
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) {
|
||||
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked, RankingMetrics rankingMetricType) {
|
||||
super(raceIdentifier, trackedRace);
|
||||
this.regattaName = raceIdentifier.getRegattaName();
|
||||
this.isTracked = isCurrentlyTracked;
|
||||
this.rankingMetricType = rankingMetricType;
|
||||
}
|
||||
|
||||
public RegattaAndRaceIdentifier getRaceIdentifier() {
|
||||
return new RegattaNameAndRaceName(regattaName, getName());
|
||||
}
|
||||
|
||||
public RankingMetrics getRankingMetricType() {
|
||||
return rankingMetricType;
|
||||
}
|
||||
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.sap.sailing.domain.abstractlog.orc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class RaceLogORCScratchBoatAnalyzer extends BaseLogAnalyzer<RaceLog, RaceLogEvent, RaceLogEventVisitor, Pair<Competitor, RaceLogORCScratchBoatEvent>> {
|
||||
private static final Logger logger = Logger.getLogger(RaceLogORCScratchBoatAnalyzer.class.getName());
|
||||
private final Function<Serializable, Competitor> competitorsById;
|
||||
|
||||
public RaceLogORCScratchBoatAnalyzer(RaceLog log, Function<Serializable, Competitor> competitorsById) {
|
||||
super(log);
|
||||
this.competitorsById = competitorsById;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pair<Competitor, RaceLogORCScratchBoatEvent> performAnalysis() {
|
||||
for (final RaceLogEvent o : getLog().getUnrevokedEventsDescending()) {
|
||||
if (o instanceof RaceLogORCScratchBoatEvent) {
|
||||
RaceLogORCScratchBoatEvent event = (RaceLogORCScratchBoatEvent) o;
|
||||
final Serializable competitorId = event.getCompetitorId();
|
||||
final Competitor competitor = competitorsById.apply(competitorId);
|
||||
if (competitor != null) {
|
||||
return new Pair<>(competitor, event);
|
||||
} else {
|
||||
logger.warning("Unable to find competitor with ID " + competitorId
|
||||
+ " as an ORC Performance Curve scratch boat. Race log event is ignored.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+6
-19
@@ -1,40 +1,27 @@
|
||||
package com.sap.sailing.domain.abstractlog.orc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class RaceLogORCScratchBoatFinder extends BaseLogAnalyzer<RaceLog, RaceLogEvent, RaceLogEventVisitor, Competitor> {
|
||||
private static final Logger logger = Logger.getLogger(RaceLogORCScratchBoatFinder.class.getName());
|
||||
private final Map<Serializable, Competitor> competitorsById;
|
||||
private final Function<Serializable, Competitor> competitorsById;
|
||||
|
||||
public RaceLogORCScratchBoatFinder(RaceLog log, Map<Serializable, Competitor> competitorsById) {
|
||||
public RaceLogORCScratchBoatFinder(RaceLog log, Function<Serializable, Competitor> competitorsById) {
|
||||
super(log);
|
||||
this.competitorsById = competitorsById;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Competitor performAnalysis() {
|
||||
for (final RaceLogEvent o : getLog().getUnrevokedEventsDescending()) {
|
||||
if (o instanceof RaceLogORCScratchBoatEvent) {
|
||||
RaceLogORCScratchBoatEvent event = (RaceLogORCScratchBoatEvent) o;
|
||||
final Serializable competitorId = event.getCompetitorId();
|
||||
final Competitor competitor = competitorsById.get(competitorId);
|
||||
if (competitor != null) {
|
||||
return competitor;
|
||||
} else {
|
||||
logger.warning("Unable to find competitor with ID " + competitorId
|
||||
+ " as an ORC Performance Curve scratch boat. Race log event is ignored.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
final Pair<Competitor, RaceLogORCScratchBoatEvent> preResult = new RaceLogORCScratchBoatAnalyzer(getLog(), competitorsById).analyze();
|
||||
return preResult == null ? null : preResult.getA();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
|
||||
PlacemarkOrderDTO racePlaces = withGeoLocationData ? getRacePlaces(trackedRace) : null;
|
||||
TrackedRaceDTO trackedRaceDTO = createTrackedRaceDTO(trackedRace);
|
||||
RaceDTO raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, trackedRegattaRegistry.isRaceBeingTracked(
|
||||
trackedRace.getTrackedRegatta().getRegatta(), trackedRace.getRace()));
|
||||
trackedRace.getTrackedRegatta().getRegatta(), trackedRace.getRace()), trackedRace.getRankingMetric()==null?null:trackedRace.getRankingMetric().getType());
|
||||
raceDTO.places = racePlaces;
|
||||
updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
|
||||
return raceDTO;
|
||||
|
||||
+7
-1
@@ -41,6 +41,7 @@ import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.common.orc.ORCCertificate;
|
||||
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse;
|
||||
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg;
|
||||
@@ -115,6 +116,11 @@ public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRanki
|
||||
updateCourseFromRaceLogs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RankingMetrics getType() {
|
||||
return RankingMetrics.ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND;
|
||||
}
|
||||
|
||||
private void initializeListeners() {
|
||||
certificatesAndCourseAndScratchBoatFromRaceLogUpdater = createCertificatesFromRaceLogAndCourseAndScratchBoatUpdater();
|
||||
certificatesFromRegattaLogUpdater = createCertificatesFromRegattaLogUpdater();
|
||||
@@ -245,7 +251,7 @@ public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRanki
|
||||
private void updateScratchBoatFromLogs() {
|
||||
Competitor scratchBoatFromLog = null;
|
||||
for (final RaceLog raceLog : getTrackedRace().getAttachedRaceLogs()) {
|
||||
scratchBoatFromLog = new RaceLogORCScratchBoatFinder(raceLog, competitorsById).analyze();
|
||||
scratchBoatFromLog = new RaceLogORCScratchBoatFinder(raceLog, competitorId->competitorsById.get(competitorId)).analyze();
|
||||
if (scratchBoatFromLog != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
+6
@@ -13,6 +13,7 @@ import java.util.logging.Logger;
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.orc.ORCPerformanceCurve;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
@@ -39,6 +40,11 @@ public class ORCPerformanceCurveRankingMetric extends ORCPerformanceCurveByImpli
|
||||
super(trackedRace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RankingMetrics getType() {
|
||||
return RankingMetrics.ORC_PERFORMANCE_CURVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* As opposed to before 2015 when implied wind was the only ranking criterion at all times, in 2015
|
||||
* it was decided to rank based on corrected times, and corrected times shall be computed not by mapping
|
||||
|
||||
+6
@@ -5,6 +5,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
@@ -29,6 +30,11 @@ public class ORCPerformanceCurveRankingMetricLeaderForBaseline extends ORCPerfor
|
||||
super(trackedRace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RankingMetrics getType() {
|
||||
return RankingMetrics.ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Competitor getBaseLineCompetitorForAbsoluteCorrectedTimes(TimePoint timePoint,
|
||||
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
|
||||
|
||||
+6
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
@@ -27,6 +28,11 @@ public class OneDesignRankingMetric extends NonPerformanceCurveRankingMetric {
|
||||
super(trackedRace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RankingMetrics getType() {
|
||||
return RankingMetrics.ONE_DESIGN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<Competitor> getRaceRankingComparator(TimePoint timePoint, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
|
||||
return new RaceRankComparator(getTrackedRace(), timePoint, cache);
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.function.Function;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
@@ -141,6 +142,8 @@ public interface RankingMetric extends Serializable {
|
||||
* @return the tracked race to which this ranking metric is specific
|
||||
*/
|
||||
TrackedRace getTrackedRace();
|
||||
|
||||
RankingMetrics getType();
|
||||
|
||||
default Comparator<Competitor> getRaceRankingComparator(TimePoint timePoint) {
|
||||
return getRaceRankingComparator(timePoint, new LeaderboardDTOCalculationReuseCache(timePoint));
|
||||
|
||||
+6
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.Mile;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
|
||||
@@ -76,6 +77,11 @@ public class TimeOnTimeAndDistanceRankingMetric extends NonPerformanceCurveRanki
|
||||
this.timeOnDistanceFactorNauticalMile = timeOnDistanceFactorInSecondsPerNauticalMile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RankingMetrics getType() {
|
||||
return RankingMetrics.TIME_ON_TIME_AND_DISTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ranks the competitors by their average corrected velocity made good, determined by the following formula:
|
||||
*
|
||||
|
||||
+60
@@ -8,6 +8,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
@@ -30,6 +31,8 @@ import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||
@@ -815,4 +818,61 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel
|
||||
stringMessages, errorReporter, new RaceBoatCertificatesPanel(sailingService, userService, object.getC(), object.getA(), object.getB(), stringMessages, errorReporter));
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
protected void selectScratchBoat(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
|
||||
sailingService.getORCPerformanceCurveScratchBoat(object.getC().getName(), object.getA().getName(), object.getB().getName(), new AsyncCallback<CompetitorDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorObtainingScratchBoat(caught.getMessage()), /* silent */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(CompetitorDTO scratchBoatSoFar) {
|
||||
new CompetitorSelectionDialog(sailingService, userService, errorReporter,
|
||||
stringMessages.selectScratchBoat(), stringMessages.selectScratchBoat(), getRaceCompetitorProvider(object), stringMessages, scratchBoatSoFar,
|
||||
new DialogCallback<CompetitorDTO>() {
|
||||
@Override
|
||||
public void ok(CompetitorDTO newScratchBoat) {
|
||||
sailingService.setORCPerformanceCurveScratchBoat(object.getC().getName(), object.getA().getName(), object.getB().getName(),
|
||||
newScratchBoat, new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorSettingScratchBoat(caught.getMessage()), /* silent */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
Notification.notify(stringMessages.scratchBoatSetSuccessfully(), NotificationType.SUCCESS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {}
|
||||
}).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps in obtaining competitors for a specific "race slot" identified by leaderboard name, race column name and
|
||||
* fleet name. In particular, the implementation is expected to return a consumer that when called with a callback
|
||||
* fetches the competitors for the particular race identified by {@code raceSlotIdentifier} and sends them to the
|
||||
* callback's {@link AsyncCallback#onSuccess(Object)} method.
|
||||
*/
|
||||
protected Consumer<AsyncCallback<Iterable<? extends CompetitorDTO>>> getRaceCompetitorProvider(
|
||||
RaceColumnDTOAndFleetDTOWithNameBasedEquality raceSlotIdentifier) {
|
||||
return callback -> sailingService.getCompetitorsAndBoatsOfRace(raceSlotIdentifier.getC().getName(),
|
||||
raceSlotIdentifier.getA().getName(), raceSlotIdentifier.getB().getName(), new AsyncCallback<Map<? extends CompetitorDTO, BoatDTO>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Map<? extends CompetitorDTO, BoatDTO> competitorToBoatMap) {
|
||||
callback.onSuccess(competitorToBoatMap.keySet());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+3
@@ -130,4 +130,7 @@ interface AdminConsoleResources extends ClientBundle {
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/certificates.png")
|
||||
ImageResource updateCertificatesIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/scratchBoat.png")
|
||||
ImageResource scratchBoatIcon();
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
|
||||
/**
|
||||
* A dialog that can be used to select a single competitor. The dialog can be customized with a title and message. If a
|
||||
* competitor is specified as the object to select initially and that object is contained in the result of fetching the
|
||||
* competitors, it is selected in the table.
|
||||
* <p>
|
||||
*
|
||||
* For fetching the competitors, a {@link Consumer} of an {@link AsyncCallback} must be provided. It is expected that
|
||||
* this consumer "consumes" the callback by obtaining a list of competitors, possibly asynchronously, and sending the
|
||||
* result to the callback's {@link AsyncCallback#onSuccess(Object)} method.<p>
|
||||
*
|
||||
* The dialog's result is the {@link CompetitorDTO} selected when the dialog is confirmed using the OK button. When
|
||||
* no selection currently exists, {@code null} will result.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class CompetitorSelectionDialog extends DataEntryDialog<CompetitorDTO> {
|
||||
private final CompetitorTableWrapper<RefreshableSingleSelectionModel<CompetitorDTO>> competitorTable;
|
||||
|
||||
public CompetitorSelectionDialog(SailingServiceAsync sailingService, UserService userService,
|
||||
ErrorReporter errorReporter, String title, String message,
|
||||
Consumer<AsyncCallback<Iterable<? extends CompetitorDTO>>> competitorProvider, StringMessages stringMessages,
|
||||
CompetitorDTO initialSelection,
|
||||
DialogCallback<CompetitorDTO> callback) {
|
||||
super(title, message, stringMessages.ok(), stringMessages.cancel(), /* validator */ null, callback);
|
||||
competitorTable = new CompetitorTableWrapper<>(sailingService, userService, stringMessages, errorReporter,
|
||||
/* multiSelection */ false, /* enablePager */ true, /* filter with boat */ false,
|
||||
/* filter without boat */ false);
|
||||
competitorProvider.accept(new AsyncCallback<Iterable<? extends CompetitorDTO>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorLoadingCompetitors(caught.getMessage()), /* silentMode */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Iterable<? extends CompetitorDTO> result) {
|
||||
competitorTable.refreshCompetitorList(result);
|
||||
if (initialSelection != null) {
|
||||
competitorTable.getSelectionModel().setSelected(initialSelection, /* selected */ true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
final VerticalPanel result = new VerticalPanel();
|
||||
result.add(competitorTable);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompetitorDTO getResult() {
|
||||
return competitorTable.getSelectionModel().getSelectedObject();
|
||||
}
|
||||
}
|
||||
+20
-5
@@ -70,6 +70,18 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
|
||||
private final boolean filterCompetitorsWithBoat;
|
||||
private final boolean filterCompetitorsWithoutBoat;
|
||||
|
||||
/**
|
||||
* @param filterCompetitorsWithBoat
|
||||
* relevant if {@link #refreshCompetitorList(String)} or {@link #refreshCompetitorList(String, Callback)}
|
||||
* will be called using {@code null} for the leaderboard name, hence requesting <em>all</em> competitors
|
||||
* to be loaded. In this case, competitors with boat will be fetched only if this flag is
|
||||
* {@code false}.
|
||||
* @param filterCompetitorsWithoutBoat
|
||||
* relevant if {@link #refreshCompetitorList(String)} or {@link #refreshCompetitorList(String, Callback)}
|
||||
* will be called using {@code null} for the leaderboard name, hence requesting <em>all</em> competitors
|
||||
* to be loaded. In this case, competitors without boat will be fetched only if this flag is
|
||||
* {@code false}.
|
||||
*/
|
||||
public CompetitorTableWrapper(SailingServiceAsync sailingService, UserService userService, StringMessages stringMessages, ErrorReporter errorReporter,
|
||||
boolean multiSelection, boolean enablePager, boolean filterCompetitorsWithBoat, boolean filterCompetitorsWithoutBoat) {
|
||||
super(sailingService, stringMessages, errorReporter, multiSelection, enablePager,
|
||||
@@ -366,7 +378,7 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
|
||||
return filterField;
|
||||
}
|
||||
|
||||
public void refreshCompetitorList(Iterable<CompetitorDTO> competitors) {
|
||||
public void refreshCompetitorList(Iterable<? extends CompetitorDTO> competitors) {
|
||||
getFilteredCompetitors(competitors);
|
||||
}
|
||||
|
||||
@@ -375,10 +387,13 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leaderboardName If null, all existing competitors are loaded
|
||||
* @param leaderboardName
|
||||
* If {@code null}, all existing competitors are loaded.
|
||||
* @param callback
|
||||
* if not {@code null}, its {@code AsyncCallback#onSuccess(Object)} method will be called after
|
||||
* successfully refreshing the competitors
|
||||
*/
|
||||
public void refreshCompetitorList(String leaderboardName, final Callback<Iterable<CompetitorDTO>,
|
||||
Throwable> callback) {
|
||||
public void refreshCompetitorList(String leaderboardName, final Callback<Iterable<CompetitorDTO>, Throwable> callback) {
|
||||
final AsyncCallback<Iterable<CompetitorDTO>> myCallback = new AsyncCallback<Iterable<CompetitorDTO>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
@@ -404,7 +419,7 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
|
||||
}
|
||||
}
|
||||
|
||||
private void getFilteredCompetitors(Iterable<CompetitorDTO> result) {
|
||||
private void getFilteredCompetitors(Iterable<? extends CompetitorDTO> result) {
|
||||
filterField.updateAll(result);
|
||||
}
|
||||
|
||||
|
||||
+10
-6
@@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
@@ -124,8 +125,14 @@ public abstract class CourseManagementWidget implements IsWidget {
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param showOrcPcsLegEditActions
|
||||
* Depending on the ranking metric it may or may not make sense to show the user the actions to maintain
|
||||
* ORC PCS leg data. By default, these actions are enabled, particularly to cover the case where this
|
||||
* widget is used without an existing {@code TrackedRace} and only with a race log.
|
||||
*/
|
||||
public CourseManagementWidget(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
final StringMessages stringMessages, final UserService userService) {
|
||||
final StringMessages stringMessages, final UserService userService, final Supplier<Boolean> showOrcPcsLegEditActions) {
|
||||
this.sailingService = sailingService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.stringMessages = stringMessages;
|
||||
@@ -162,7 +169,7 @@ public abstract class CourseManagementWidget implements IsWidget {
|
||||
mainPanel.setWidget(1, 1, controlPointsBtnsPanel);
|
||||
mainPanel.setWidget(1, 2, marksBtnsPanel);
|
||||
final AccessControlledActionsColumn<WaypointDTO, WaypointImagesBarCell> waypointsActionColumn = create(
|
||||
new WaypointImagesBarCell(stringMessages, waypoints.getDataProvider()), userService,
|
||||
new WaypointImagesBarCell(stringMessages, waypoints.getDataProvider(), showOrcPcsLegEditActions), userService,
|
||||
s -> securedDtoForWaypointsPermissionCheck);
|
||||
// update permission for tracked race is required for deleting waypoints...
|
||||
waypointsActionColumn.addAction(DefaultActions.DELETE.name(), DefaultActions.UPDATE,
|
||||
@@ -405,7 +412,7 @@ public abstract class CourseManagementWidget implements IsWidget {
|
||||
}).show();
|
||||
}
|
||||
|
||||
public void refresh(){};
|
||||
public abstract void refresh();
|
||||
|
||||
protected void updateWaypointsAndControlPoints(RaceCourseDTO raceCourseDTO, String leaderboardName) {
|
||||
this.sailingService.getLeaderboardWithSecurity(leaderboardName,
|
||||
@@ -431,7 +438,6 @@ public abstract class CourseManagementWidget implements IsWidget {
|
||||
waypoints.getDataProvider().getList().clear();
|
||||
multiMarkControlPoints.getDataProvider().getList().clear();
|
||||
waypoints.getDataProvider().getList().addAll(raceCourseDTO.waypoints);
|
||||
|
||||
Map<String, ControlPointDTO> noDuplicateCPs = new HashMap<>();
|
||||
for (ControlPointDTO controlPoint : raceCourseDTO.getControlPoints()) {
|
||||
if (controlPoint instanceof GateDTO) {
|
||||
@@ -439,9 +445,7 @@ public abstract class CourseManagementWidget implements IsWidget {
|
||||
}
|
||||
}
|
||||
multiMarkControlPoints.getDataProvider().getList().addAll(noDuplicateCPs.values());
|
||||
|
||||
updateWaypointButtons();
|
||||
|
||||
final boolean hasUpdatePermission = userService.hasPermission(securedDTO, DefaultActions.UPDATE);
|
||||
insertWaypointAfter.setVisible(hasUpdatePermission);
|
||||
insertWaypointBefore.setVisible(hasUpdatePermission);
|
||||
|
||||
-6
@@ -10,11 +10,6 @@ import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Daniel Lisunkin (i505543)
|
||||
*
|
||||
*/
|
||||
public class EditCompetitorsDialog extends DataEntryDialog<List<CompetitorWithBoatDTO>> {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final UserService userService;
|
||||
@@ -51,7 +46,6 @@ public class EditCompetitorsDialog extends DataEntryDialog<List<CompetitorWithBo
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
CompetitorPanel competitorPanel = new CompetitorPanel(sailingService, userService, leaderboardName, stringMessages, errorReporter);
|
||||
|
||||
return competitorPanel;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -2,11 +2,12 @@ package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import static com.sap.sailing.domain.common.security.SecuredDomainType.LEADERBOARD;
|
||||
import static com.sap.sailing.domain.common.security.SecuredDomainType.REGATTA;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_CERTIFICATE_ASSIGNMENT;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_EDIT;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_CERTIFICATE_ASSIGNMENT;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_REFRESH_RACELOG;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_REMOVE;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SCRATCH_BOAT_SELECTION;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SET_FINISHING_AND_FINISH_TIME;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SET_STARTTIME;
|
||||
import static com.sap.sailing.gwt.ui.adminconsole.LeaderboardRaceConfigImagesBarCell.ACTION_SHOW_RACELOG;
|
||||
@@ -540,8 +541,8 @@ public class LeaderboardConfigPanel extends AbstractLeaderboardConfigPanel
|
||||
actionsColumn.addAction(ACTION_SHOW_RACELOG, UPDATE, object -> showRaceLog(object.getA(), object.getB()));
|
||||
actionsColumn.addAction(ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS, UPDATE,
|
||||
object -> editCompetitorToBoatMappings(object.getA(), object.getB()));
|
||||
actionsColumn.addAction(ACTION_CERTIFICATE_ASSIGNMENT, READ,
|
||||
object -> assignCertificates(object));
|
||||
actionsColumn.addAction(ACTION_CERTIFICATE_ASSIGNMENT, READ, object -> assignCertificates(object));
|
||||
actionsColumn.addAction(ACTION_SCRATCH_BOAT_SELECTION, READ, object -> selectScratchBoat(object));
|
||||
racesTable.addColumn(isMedalRaceCheckboxColumn, stringMessages.medalRace());
|
||||
racesTable.addColumn(isLinkedRaceColumn, stringMessages.islinked());
|
||||
racesTable.addColumn(explicitFactorColumn, stringMessages.factor());
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ public class LeaderboardRaceConfigImagesBarCell extends ImagesBarCell {
|
||||
public final static String ACTION_SHOW_RACELOG = "ACTION_SHOW_RACELOG";
|
||||
public final static String ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS = "ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS";
|
||||
public final static String ACTION_CERTIFICATE_ASSIGNMENT = "ACTION_CERTIFICATE_ASSIGNMENT";
|
||||
public final static String ACTION_SCRATCH_BOAT_SELECTION = "ACTION_SCRATCH_BOAT_SELECTION";
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
private final SelectedLeaderboardProvider<? extends StrippedLeaderboardDTO> selectedLeaderboardProvider;
|
||||
@@ -53,6 +54,7 @@ public class LeaderboardRaceConfigImagesBarCell extends ImagesBarCell {
|
||||
}
|
||||
if (raceHasORCRankingMetric(object)) {
|
||||
result.add(new ImageSpec(ACTION_CERTIFICATE_ASSIGNMENT, stringMessages.assignCertificates(), resources.updateCertificatesIcon()));
|
||||
result.add(new ImageSpec(ACTION_SCRATCH_BOAT_SELECTION, stringMessages.selectScratchBoat(), resources.scratchBoatIcon()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+23
-13
@@ -9,6 +9,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl;
|
||||
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
@@ -35,7 +36,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
|
||||
RegattaRefresher regattaRefresher, final StringMessages stringMessages, final UserService userService) {
|
||||
super(sailingService, userService, errorReporter, regattaRefresher, /* actionButtonsEnabled */ false, stringMessages);
|
||||
courseManagementWidget = new CourseManagementWidget(sailingService, errorReporter, stringMessages,
|
||||
userService) {
|
||||
userService, ()->selectedRaceHasOrcPcsRankingMetric()) {
|
||||
@Override
|
||||
protected void save() {
|
||||
sailingService.updateRaceCourse(singleSelectedRace, createWaypointPairs(), new AsyncCallback<Void>() {
|
||||
@@ -94,18 +95,20 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
|
||||
}
|
||||
|
||||
private void refreshORCPerformanceCurveLegs() {
|
||||
sailingService.getORCPerformanceCurveLegInfo(singleSelectedRace,
|
||||
new AsyncCallback<Map<Integer, ORCPerformanceCurveLegImpl>>() {
|
||||
@Override
|
||||
public void onSuccess(Map<Integer, ORCPerformanceCurveLegImpl> result) {
|
||||
refreshORCPerformanceCurveLegs(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load ORC Performance Curve leg information: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
if (singleSelectedRace != null) {
|
||||
sailingService.getORCPerformanceCurveLegInfo(singleSelectedRace,
|
||||
new AsyncCallback<Map<Integer, ORCPerformanceCurveLegImpl>>() {
|
||||
@Override
|
||||
public void onSuccess(Map<Integer, ORCPerformanceCurveLegImpl> result) {
|
||||
refreshORCPerformanceCurveLegs(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Could not load ORC Performance Curve leg information: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
FlowPanel courseManagementPanel = new FlowPanel();
|
||||
@@ -134,6 +137,13 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
|
||||
this.selectedRaceContentPanel.add(buttonsPanel);
|
||||
}
|
||||
|
||||
private boolean selectedRaceHasOrcPcsRankingMetric() {
|
||||
final RankingMetrics rankingMetricType = selectedRaceDTO == null ? null : selectedRaceDTO.getRankingMetricType();
|
||||
return rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE ||
|
||||
rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND ||
|
||||
rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
void refreshSelectedRaceData() {
|
||||
courseManagementWidget.refresh();
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget {
|
||||
public RaceLogCourseManagementWidget(final SailingServiceAsync sailingService, final ErrorReporter errorReporter,
|
||||
final StringMessages stringMessages, final String leaderboardName, final String raceColumnName,
|
||||
final String fleetName, final UserService userService) {
|
||||
super(sailingService, errorReporter, stringMessages, userService);
|
||||
super(sailingService, errorReporter, stringMessages, userService, /* always show ORC OCS leg data actions */ ()->true);
|
||||
this.leaderboardName = leaderboardName;
|
||||
this.raceColumnName = raceColumnName;
|
||||
this.fleetName = fleetName;
|
||||
|
||||
+13
-3
@@ -17,6 +17,7 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
|
||||
public final static String ACTION_COMPETITOR_REGISTRATIONS = "ACTION_COMPETITOR_REGISTRATIONS";
|
||||
public final static String ACTION_DEFINE_COURSE = "ACTION_DEFINE_COURSE";
|
||||
public final static String ACTION_COPY = "ACTION_COPY";
|
||||
public final static String ACTION_UNLINK = "ACTION_UNLINK";
|
||||
public final static String ACTION_EDIT = "ACTION_EDIT";
|
||||
public final static String ACTION_REFRESH_RACELOG = "ACTION_REFRESH_RACE_LOG";
|
||||
public final static String ACTION_SET_STARTTIME = "ACTION_SET_STARTTIME";
|
||||
@@ -27,6 +28,7 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
|
||||
public final static String ACTION_START_TRACKING = "ACTION_START_TRACKING";
|
||||
public final static String ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS = "ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS";
|
||||
public static final String ACTION_CERTIFICATE_ASSIGNMENT = "ACTION_CERTIFICATE_ASSIGNMENT";
|
||||
public static final String ACTION_SCRATCH_BOAT_SELECTION = "ACTION_SCRATCH_BOAT_SELECTION";
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
private SmartphoneTrackingEventManagementPanel smartphoneTrackingEventManagementPanel;
|
||||
@@ -51,6 +53,7 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
|
||||
result.add(new ImageSpec(ACTION_COPY, stringMessages.copyCourseAndCompetitors(), makeImagePrototype(resources.copy())));
|
||||
}
|
||||
result.add(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(IconResources.INSTANCE.editIcon())));
|
||||
result.add(new ImageSpec(ACTION_UNLINK, stringMessages.actionRaceUnlink(), makeImagePrototype(resources.unlinkIcon())));
|
||||
result.add(new ImageSpec(ACTION_REFRESH_RACELOG, stringMessages.refreshRaceLog(), makeImagePrototype(resources.reloadIcon())));
|
||||
result.add(new ImageSpec(ACTION_SET_STARTTIME, stringMessages.setStartTime(), makeImagePrototype(resources.clockIcon())));
|
||||
result.add(new ImageSpec(ACTION_SET_FINISHING_AND_FINISH_TIME, stringMessages.setFinishingAndFinishTime(), makeImagePrototype(resources.blueSmall())));
|
||||
@@ -67,14 +70,21 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe
|
||||
if (smartphoneTrackingEventManagementPanel.getSelectedLeaderboard().canBoatsOfCompetitorsChangePerRace) {
|
||||
result.add(new ImageSpec(ACTION_EDIT_COMPETITOR_TO_BOAT_MAPPINGS, stringMessages.actionShowCompetitorToBoatAssignments(), makeImagePrototype(resources.sailboatIcon())));
|
||||
}
|
||||
if (raceHasORCRankingMetric(object)) {
|
||||
if (raceCouldHaveORCRankingMetric(object)) {
|
||||
result.add(new ImageSpec(ACTION_CERTIFICATE_ASSIGNMENT, stringMessages.assignCertificates(), resources.updateCertificatesIcon()));
|
||||
result.add(new ImageSpec(ACTION_SCRATCH_BOAT_SELECTION, stringMessages.selectScratchBoat(), resources.scratchBoatIcon()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean raceHasORCRankingMetric(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
|
||||
// TODO Implement RaceLogTrackingEventManagementRaceImagesBarCell.raceHasORCRankingMetric(...)
|
||||
/**
|
||||
* The problem with these race log-dependent ORC PCS events is this: at a later point a user could theoretically
|
||||
* attach an ORC PCS race to the same race column. Corner case... For now we always allow users to make statements
|
||||
* about ORC certificates at race level.
|
||||
*
|
||||
* @return {@code true}
|
||||
*/
|
||||
private boolean raceCouldHaveORCRankingMetric(RaceColumnDTOAndFleetDTOWithNameBasedEquality object) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -300,11 +300,11 @@ public class SmartphoneTrackingEventManagementPanel
|
||||
DefaultActions.UPDATE, this::handleDefineCourse);
|
||||
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_COPY, DefaultActions.UPDATE,
|
||||
this::handleCopy);
|
||||
raceActionColumn.addAction(LeaderboardRaceConfigImagesBarCell.ACTION_EDIT, DefaultActions.UPDATE,
|
||||
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_EDIT, DefaultActions.UPDATE,
|
||||
this::editRaceColumnOfLeaderboard);
|
||||
raceActionColumn.addAction(LeaderboardRaceConfigImagesBarCell.ACTION_UNLINK, DefaultActions.UPDATE,
|
||||
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_UNLINK, DefaultActions.UPDATE,
|
||||
t -> unlinkRaceColumnFromTrackedRace(t.getA().getRaceColumnName(), t.getB()));
|
||||
raceActionColumn.addAction(LeaderboardRaceConfigImagesBarCell.ACTION_REFRESH_RACELOG, DefaultActions.UPDATE,
|
||||
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_REFRESH_RACELOG, DefaultActions.UPDATE,
|
||||
t -> refreshRaceLog(t.getA(), t.getB(), true));
|
||||
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_SET_STARTTIME,
|
||||
DefaultActions.UPDATE, this::setStartTime);
|
||||
@@ -324,6 +324,8 @@ public class SmartphoneTrackingEventManagementPanel
|
||||
DefaultActions.UPDATE, this::showCompetitorToBoatMappings);
|
||||
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_CERTIFICATE_ASSIGNMENT, READ,
|
||||
t -> assignCertificates(t));
|
||||
raceActionColumn.addAction(RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_SCRATCH_BOAT_SELECTION, READ,
|
||||
t -> selectScratchBoat(t));
|
||||
|
||||
racesTable.addColumn(raceLogTrackingStateColumn, stringMessages.raceStatusColumn());
|
||||
racesTable.addColumn(trackerStateColumn, stringMessages.trackerStatus());
|
||||
|
||||
+11
-5
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
@@ -15,9 +16,12 @@ public class WaypointImagesBarCell extends DefaultActionsImagesBarCell {
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
private final StringMessages stringMessages;
|
||||
private final ListDataProvider<WaypointDTO> waypointList;
|
||||
private final Supplier<Boolean> showOrcPcsLegActions;
|
||||
|
||||
public WaypointImagesBarCell(final StringMessages stringMessages, ListDataProvider<WaypointDTO> waypointList) {
|
||||
public WaypointImagesBarCell(final StringMessages stringMessages, ListDataProvider<WaypointDTO> waypointList,
|
||||
Supplier<Boolean> showOrcPcsLegActions) {
|
||||
super(stringMessages);
|
||||
this.showOrcPcsLegActions = showOrcPcsLegActions;
|
||||
this.stringMessages = stringMessages;
|
||||
this.waypointList = waypointList;
|
||||
}
|
||||
@@ -27,10 +31,12 @@ public class WaypointImagesBarCell extends DefaultActionsImagesBarCell {
|
||||
final WaypointDTO waypoint = (WaypointDTO) getContext().getKey();
|
||||
final List<ImageSpec> imageSpecs = new ArrayList<>();
|
||||
imageSpecs.add(getDeleteImageSpec());
|
||||
if (waypoint != waypointList.getList().get(0)) {
|
||||
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_LEG, stringMessages.actionDefineLegForOrcPcs(), resources.orcPcsDefineLegIcon()));
|
||||
} else {
|
||||
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_ALL_LEGS, stringMessages.actionDefineAllLegsForOrcPcs(), resources.orcPcsDefineAllLegsIcon()));
|
||||
if (showOrcPcsLegActions.get()) {
|
||||
if (waypoint != waypointList.getList().get(0)) {
|
||||
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_LEG, stringMessages.actionDefineLegForOrcPcs(), resources.orcPcsDefineLegIcon()));
|
||||
} else {
|
||||
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_ALL_LEGS, stringMessages.actionDefineAllLegsForOrcPcs(), resources.orcPcsDefineAllLegsIcon()));
|
||||
}
|
||||
}
|
||||
return imageSpecs;
|
||||
}
|
||||
|
||||
+5
@@ -1248,4 +1248,9 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
|
||||
|
||||
Triple<Integer, Integer, Integer> assignORCPerformanceCurveCertificates(String leaderboardName,
|
||||
Map<String, ORCCertificate> certificatesForBoatsWithIdAsString) throws IOException, NotFoundException;
|
||||
|
||||
CompetitorDTO getORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException;
|
||||
|
||||
void setORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName,
|
||||
CompetitorDTO newScratchBoat) throws NotFoundException;
|
||||
}
|
||||
|
||||
+6
@@ -1172,4 +1172,10 @@ public interface SailingServiceAsync extends FileStorageManagementGwtServiceAsyn
|
||||
void assignORCPerformanceCurveCertificates(String leaderboardName,
|
||||
Map<String, ORCCertificate> certificatesForBoatsWithIdAsString,
|
||||
AsyncCallback<Triple<Integer, Integer, Integer>> callback);
|
||||
|
||||
void getORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName,
|
||||
AsyncCallback<CompetitorDTO> asyncCallback);
|
||||
|
||||
void setORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName, CompetitorDTO newScratchBoat,
|
||||
AsyncCallback<Void> asyncCallback);
|
||||
}
|
||||
|
||||
+4
@@ -2300,4 +2300,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String totalDistance();
|
||||
String setAllLegsToType();
|
||||
String desiredTotalDistanceInNauticalMiles();
|
||||
String selectScratchBoat();
|
||||
String errorObtainingScratchBoat(String message);
|
||||
String errorSettingScratchBoat(String message);
|
||||
String scratchBoatSetSuccessfully();
|
||||
}
|
||||
|
||||
+5
-1
@@ -2303,4 +2303,8 @@ trackedDistanceInNauticalMiles=Tracked leg distance (NM)
|
||||
useTrackedData=Use tracked leg data
|
||||
totalDistance=Total Distance (NM)
|
||||
setAllLegsToType=Set all legs to type
|
||||
desiredTotalDistanceInNauticalMiles=Desired Total Distance (NM)
|
||||
desiredTotalDistanceInNauticalMiles=Desired Total Distance (NM)
|
||||
selectScratchBoat=Select scratch boat
|
||||
errorObtainingScratchBoat=Error obtaining scratch boat: {0}
|
||||
errorSettingScratchBoat=Error setting scratch boat: {0}
|
||||
scratchBoatSetSuccessfully=Scratch boat set successfully.
|
||||
+5
-1
@@ -2295,4 +2295,8 @@ trackedDistanceInNauticalMiles=Getrackte Schenkel-Distanz (NM)
|
||||
useTrackedData=Tracking-Werte verwenden
|
||||
totalDistance=Gesamtdistanz (NM)
|
||||
setAllLegsToType=Typ für alle Bahnschenkel setzen
|
||||
desiredTotalDistanceInNauticalMiles=Gewünschte Gesamtdistanz (NM)
|
||||
desiredTotalDistanceInNauticalMiles=Gewünschte Gesamtdistanz (NM)
|
||||
selectScratchBoat="Scratch-Boot" auswählen
|
||||
errorObtainingScratchBoat=Fehler beim Laden des "Scratch-Bootes": {0}
|
||||
errorSettingScratchBoat=Fehler beim Setzen des "Scratch-Bootes": {0}
|
||||
scratchBoatSetSuccessfully="Scratch-Boot" erfolgreich geändert.
|
||||
+57
-41
@@ -88,9 +88,13 @@ import com.sap.sailing.domain.abstractlog.orc.RaceLogORCCertificateAssignmentFin
|
||||
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataEvent;
|
||||
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCLegDataEventFinder;
|
||||
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCScratchBoatAnalyzer;
|
||||
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCScratchBoatEvent;
|
||||
import com.sap.sailing.domain.abstractlog.orc.RaceLogORCScratchBoatFinder;
|
||||
import com.sap.sailing.domain.abstractlog.orc.RegattaLogORCCertificateAssignmentFinder;
|
||||
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCCertificateAssignmentEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCLegDataEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.orc.impl.RaceLogORCScratchBoatEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.orc.impl.RegattaLogORCCertificateAssignmentEventImpl;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLog;
|
||||
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent;
|
||||
@@ -1278,12 +1282,16 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
|
||||
RegattaAndRaceIdentifier raceIdentifier = new RegattaNameAndRaceName(regatta.getName(), r.getName());
|
||||
TrackedRace trackedRace = getService().getExistingTrackedRace(raceIdentifier);
|
||||
TrackedRaceDTO trackedRaceDTO = null;
|
||||
final RankingMetrics rankingMetricType;
|
||||
if (trackedRace != null) {
|
||||
trackedRaceDTO = getBaseDomainFactory().createTrackedRaceDTO(trackedRace);
|
||||
rankingMetricType = trackedRace.getRankingMetric().getType();
|
||||
} else {
|
||||
rankingMetricType = null;
|
||||
}
|
||||
Map<CompetitorDTO, BoatDTO> competitorAndBoatDTOs = baseDomainFactory.convertToCompetitorAndBoatDTOs(r.getCompetitorsAndTheirBoats());
|
||||
RaceWithCompetitorsAndBoatsDTO raceDTO = new RaceWithCompetitorsAndBoatsDTO(raceIdentifier, competitorAndBoatDTOs,
|
||||
trackedRaceDTO, getService().isRaceBeingTracked(regatta, r));
|
||||
trackedRaceDTO, getService().isRaceBeingTracked(regatta, r), rankingMetricType);
|
||||
if (trackedRace != null) {
|
||||
SecurityDTOUtil.addSecurityInformation(getSecurityService(), raceDTO, trackedRace.getIdentifier());
|
||||
getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
|
||||
@@ -1993,7 +2001,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
|
||||
.convertToCompetitorAndBoatDTOs(race.getCompetitorsAndTheirBoats());
|
||||
TrackedRaceDTO trackedRaceDTO = getBaseDomainFactory().createTrackedRaceDTO(trackedRace);
|
||||
raceDTO = new RaceWithCompetitorsAndBoatsDTO(raceIdentifier, competitorsAndBoats, trackedRaceDTO,
|
||||
getService().isRaceBeingTracked(regatta, race));
|
||||
getService().isRaceBeingTracked(regatta, race), trackedRace.getRankingMetric().getType());
|
||||
if (trackedRace != null) {
|
||||
getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
|
||||
}
|
||||
@@ -5877,30 +5885,22 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
|
||||
@Override
|
||||
public Iterable<CompetitorDTO> getCompetitors(boolean filterCompetitorsWithBoat,
|
||||
boolean filterCompetitorsWithoutBoat) {
|
||||
Iterable<CompetitorDTO> result;
|
||||
CompetitorAndBoatStore competitorStore = getService().getBaseDomainFactory().getCompetitorAndBoatStore();
|
||||
final HasPermissions.Action[] requiredActionsForRead = SecuredSecurityTypes.PublicReadableActions.READ_AND_READ_PUBLIC_ACTIONS;
|
||||
final Iterable<? extends Competitor> filteredCompetitors;
|
||||
if (filterCompetitorsWithBoat == false && filterCompetitorsWithoutBoat == false) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterable<Competitor> competitors = (Iterable<Competitor>) competitorStore.getAllCompetitors();
|
||||
result = getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
|
||||
SecuredDomainType.COMPETITOR,
|
||||
requiredActionsForRead, competitors,
|
||||
this::convertToCompetitorDTO);
|
||||
filteredCompetitors = competitorStore.getAllCompetitors();
|
||||
} else if (filterCompetitorsWithBoat == true && filterCompetitorsWithoutBoat == false) {
|
||||
result = getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
|
||||
SecuredDomainType.COMPETITOR,
|
||||
requiredActionsForRead, competitorStore.getCompetitorsWithoutBoat(),
|
||||
this::convertToCompetitorDTO);
|
||||
filteredCompetitors = competitorStore.getCompetitorsWithoutBoat();
|
||||
} else if (filterCompetitorsWithBoat == false && filterCompetitorsWithoutBoat == true) {
|
||||
result = getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
|
||||
SecuredDomainType.COMPETITOR,
|
||||
requiredActionsForRead, competitorStore.getCompetitorsWithBoat(),
|
||||
this::convertToCompetitorDTO);
|
||||
filteredCompetitors = competitorStore.getCompetitorsWithBoat();
|
||||
} else {
|
||||
result = Collections.emptyList();
|
||||
filteredCompetitors = Collections.emptyList();
|
||||
}
|
||||
return result;
|
||||
return getSecurityService().mapAndFilterByAnyExplicitPermissionForCurrentUser(
|
||||
SecuredDomainType.COMPETITOR,
|
||||
requiredActionsForRead, filteredCompetitors,
|
||||
this::convertToCompetitorDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -9588,28 +9588,9 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
|
||||
|
||||
private Triple<Integer, Integer, Integer> createCertificateAssignmentsForRaceLog(String leaderboardName, String raceColumnName, String fleetName,
|
||||
Map<String, ORCCertificate> certificatesForBoatIdsAsString) throws IOException, NotFoundException {
|
||||
final Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
|
||||
if (leaderboard == null) {
|
||||
throw new NotFoundException("Leaderboard named "+leaderboardName+" not found");
|
||||
} else {
|
||||
getService().getSecurityService().checkCurrentUserUpdatePermission(leaderboard);
|
||||
if (leaderboard instanceof RegattaLeaderboard) {
|
||||
getService().getSecurityService().checkCurrentUserUpdatePermission(((RegattaLeaderboard) leaderboard).getRegatta());
|
||||
}
|
||||
final RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
|
||||
if (raceColumn == null) {
|
||||
throw new NotFoundException("Race column named "+raceColumnName+" not found in leaderboard named "+leaderboardName);
|
||||
} else {
|
||||
final Fleet fleet = raceColumn.getFleetByName(fleetName);
|
||||
if (fleet == null) {
|
||||
throw new NotFoundException("Fleet "+fleetName+" not found in race column named "+raceColumnName+" in leaderboard named "+leaderboardName);
|
||||
} else {
|
||||
final RaceLog raceLog = raceColumn.getRaceLog(fleet);
|
||||
final LogEventConstructor<RaceLogEvent, RaceLogEventVisitor> logEventConstructor = createRaceLogEventConstructor();
|
||||
return createCertificateAssignments(raceLog, logEventConstructor, certificatesForBoatIdsAsString);
|
||||
}
|
||||
}
|
||||
}
|
||||
final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
|
||||
final LogEventConstructor<RaceLogEvent, RaceLogEventVisitor> logEventConstructor = createRaceLogEventConstructor();
|
||||
return createCertificateAssignments(raceLog, logEventConstructor, certificatesForBoatIdsAsString);
|
||||
}
|
||||
|
||||
private Triple<Integer, Integer, Integer> createCertificateAssignmentsForRegatta(RegattaIdentifier regattaIdentifier,
|
||||
@@ -9734,4 +9715,39 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
|
||||
Map<String, ORCCertificate> certificatesForBoatsWithIdAsString) throws IOException, NotFoundException {
|
||||
return createCertificateAssignmentsForRaceLog(leaderboardName, raceColumnName, fleetName, certificatesForBoatsWithIdAsString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompetitorDTO getORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName) throws NotFoundException {
|
||||
final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
|
||||
final RaceLogORCScratchBoatFinder finder = new RaceLogORCScratchBoatFinder(raceLog,
|
||||
competitorId -> getService().getCompetitorAndBoatStore().getExistingCompetitorById(competitorId));
|
||||
final Competitor scratchBoat = finder.analyze();
|
||||
return scratchBoat == null ? null : convertToCompetitorDTO(scratchBoat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setORCPerformanceCurveScratchBoat(String leaderboardName, String raceColumnName, String fleetName, CompetitorDTO newScratchBoatDTO) throws NotFoundException {
|
||||
final RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName);
|
||||
final Competitor newScratchBoat = newScratchBoatDTO==null?null:
|
||||
getService().getCompetitorAndBoatStore().getExistingCompetitorById(UUIDHelper.tryUuidConversion(newScratchBoatDTO.getIdAsString()));
|
||||
final RaceLogORCScratchBoatAnalyzer analyzer = new RaceLogORCScratchBoatAnalyzer(raceLog,
|
||||
competitorId -> getService().getCompetitorAndBoatStore().getExistingCompetitorById(competitorId));
|
||||
final Pair<Competitor, RaceLogORCScratchBoatEvent> previousScratchBoatAndEvent = analyzer.analyze();
|
||||
final Competitor previousScratchBoat = previousScratchBoatAndEvent == null ? null : previousScratchBoatAndEvent.getA();
|
||||
if (!Util.equalsWithNull(newScratchBoat, previousScratchBoat)) {
|
||||
final AbstractLogEventAuthor serverAuthor = getService().getServerAuthor();
|
||||
if (previousScratchBoatAndEvent != null) {
|
||||
// revoke scratch boat setting so far:
|
||||
try {
|
||||
raceLog.revokeEvent(serverAuthor, previousScratchBoatAndEvent.getB());
|
||||
} catch (NotRevokableException e) {
|
||||
logger.log(Level.SEVERE, "Unable to revoke scratch boat definition event "+previousScratchBoatAndEvent.getB(), e);
|
||||
}
|
||||
}
|
||||
if (newScratchBoat != null) {
|
||||
final TimePoint now = MillisecondsTimePoint.now();
|
||||
raceLog.add(new RaceLogORCScratchBoatEventImpl(now, now, serverAuthor, UUID.randomUUID(), /* passId */ raceLog.getCurrentPassId(), newScratchBoat));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.shared;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.RankingMetrics;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
@@ -19,8 +20,8 @@ public class RaceWithCompetitorsAndBoatsDTO extends RaceDTO {
|
||||
RaceWithCompetitorsAndBoatsDTO() {}
|
||||
|
||||
public RaceWithCompetitorsAndBoatsDTO(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, BoatDTO> competitorsAndBoats,
|
||||
TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) {
|
||||
super(raceIdentifier, trackedRace, isCurrentlyTracked);
|
||||
TrackedRaceDTO trackedRace, boolean isCurrentlyTracked, RankingMetrics rankingMetricType) {
|
||||
super(raceIdentifier, trackedRace, isCurrentlyTracked, rankingMetricType);
|
||||
this.competitorsAndBoats = competitorsAndBoats;
|
||||
}
|
||||
|
||||
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Reference in New Issue
Block a user