items = BackupsSetupStatus.load(data.plans());
open(html, "Setup");
long todo = items.stream().filter(i -> i.state() == BackupsSetupStatus.State.TODO).count();
html.append("")
@@ -185,23 +185,27 @@ public final class BackupsHomeView
/*******************************************************************************
- ** Needs attention.
+ ** Needs attention: every Setup item that needs setup (the same list the Setup
+ ** card counts), plus plans in a problem state and recent failed runs, so the two
+ ** cards never disagree.
*******************************************************************************/
- private static void needsAttention(StringBuilder html, BackupsHomeData data, String prefix)
+ private static void needsAttention(StringBuilder html, BackupsHomeData data, List setupItems, String prefix)
{
open(html, "Needs attention");
- List plans = data.plansNeedingAttention();
- if(data.plans().isEmpty())
+ List setupTodo = setupItems.stream().filter(i -> i.state() == BackupsSetupStatus.State.TODO).toList();
+ List plans = data.plansNeedingAttention();
+ if(setupTodo.isEmpty() && plans.isEmpty() && data.failedRuns().isEmpty())
{
- empty(html, "Nothing to check yet: no plans.");
- }
- else if(plans.isEmpty() && data.failedRuns().isEmpty())
- {
- empty(html, "Nothing needs attention.");
+ empty(html, data.plans().isEmpty() ? "Nothing to check yet: no plans." : "Nothing needs attention.");
}
else
{
html.append("");
+ for(BackupsSetupStatus.Item item : setupTodo)
+ {
+ html.append("- Setup: ").append(esc(item.label())).append(": ")
+ .append(esc(item.detail())).append("
");
+ }
for(QRecord plan : plans)
{
html.append("- ").append(recordLink(prefix, BackupsTables.PLAN, plan.getValue("id"), plan.getValueString("name")))
diff --git a/src/test/java/com/kingsrook/qbits/backups/app/BackupsHomeTest.java b/src/test/java/com/kingsrook/qbits/backups/app/BackupsHomeTest.java
index 23a9d56..550cff3 100644
--- a/src/test/java/com/kingsrook/qbits/backups/app/BackupsHomeTest.java
+++ b/src/test/java/com/kingsrook/qbits/backups/app/BackupsHomeTest.java
@@ -88,7 +88,7 @@ class BackupsHomeTest
void testEmptyStates()
{
String html = BackupsHomeView.render(new BackupsHomeData(List.of(), List.of(), List.of(), List.of(), List.of(), Instant.now()), "/app");
- assertThat(html).contains("No backup plans yet").contains("Nothing to check yet").contains("No test restore yet")
+ assertThat(html).contains("No backup plans yet").contains("Setup: BackupsTestUtils.BACKUPS);
+ new BackupCatalog().insert(BackupsTables.PLAN, new LinkedHashMap<>(Map.of("name", "Offsite", "planKey", "offsite", "isActive", true, "scopeType", "INSTANCE",
+ "storageBucketAlias", "backupsAws", "pruneBucketAlias", "backupsAwsPrune")));
+
+ //////////////////////////////////////////////////////////////////////////////
+ // the aliases resolved when the plan was saved; now the bucket is gone //
+ //////////////////////////////////////////////////////////////////////////////
+ BackupsRuntime.getConfig().withStorageResolver(alias -> "backups".equals(alias) ? BackupsTestUtils.BACKUPS : null);
+
+ BackupsHomeData data = BackupsHomeData.load();
+ List setupTodo = BackupsSetupStatus.load(data.plans()).stream().filter(i -> i.state() == BackupsSetupStatus.State.TODO).toList();
+ assertThat(setupTodo).extracting(BackupsSetupStatus.Item::label).contains("Storage");
+
+ String html = BackupsHomeView.render(data, "/app");
+ String attention = html.substring(html.indexOf(">Needs attention<"));
+ attention = attention.substring(0, attention.indexOf("All runs"));
+ assertThat(attention).doesNotContain("Nothing needs attention").contains("backupsAws").contains("backupsAwsPrune");
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // every Setup TODO is listed under Needs attention (counts agree: 2 and 2) //
+ ///////////////////////////////////////////////////////////////////////////////
+ assertThat(html).contains(setupTodo.size() + " items need attention.");
+ for(BackupsSetupStatus.Item item : setupTodo)
+ {
+ assertThat(attention).contains("Setup: ", -1).length - 1).isEqualTo(setupTodo.size() + data.plansNeedingAttention().size() + data.failedRuns().size());
+ }
+
+
+
/*******************************************************************************
** The links follow the configured table path prefix.
*******************************************************************************/