This commit is contained in:
crschnick
2025-06-30 09:03:18 +00:00
parent c2a156221c
commit 6df970db2f
23 changed files with 116 additions and 51 deletions
@@ -1,4 +1,4 @@
package io.xpipe.ext.base;
package io.xpipe.app.ext;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.store.DataStore;
@@ -1,4 +1,4 @@
package io.xpipe.ext.base;
package io.xpipe.app.ext;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
@@ -575,9 +575,9 @@ public abstract class StoreEntryComp extends SimpleComp {
items.add(pinToTop);
}
if (getWrapper().getStore().getValue() instanceof FixedHierarchyStore) {
if (getWrapper().canBreakOutCategory()) {
var breakOut = new MenuItem();
var is = getWrapper().getEntry().getBreakOutCategory() != null;
var is = getWrapper().getBreakoutCategory().isPresent();
if (is) {
breakOut.textProperty().bind(AppI18n.observable("mergeCategory"));
breakOut.setGraphic(new FontIcon("mdi2c-collapse-all-outline"));
@@ -1,6 +1,7 @@
package io.xpipe.app.hub.comp;
import io.xpipe.app.action.*;
import io.xpipe.app.ext.GroupStore;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.ext.ShellStore;
import io.xpipe.app.ext.SingletonSessionStore;
@@ -14,6 +15,7 @@ import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.storage.DataStoreColor;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.FixedHierarchyStore;
import io.xpipe.app.util.PlatformThread;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.store.DataStore;
@@ -337,6 +339,11 @@ public class StoreEntryWrapper {
return false;
}
public boolean canBreakOutCategory() {
return (getStore().getValue() instanceof FixedHierarchyStore || getStore().getValue() instanceof GroupStore<?>) &&
StoreViewState.get().getParentSectionForWrapper(this).isPresent();
}
public void breakOutCategory() {
ThreadHelper.runAsync(() -> {
var cat = DataStorage.get().breakOutCategory(entry);
@@ -350,6 +357,19 @@ public class StoreEntryWrapper {
});
}
public Optional<StoreCategoryWrapper> getBreakoutCategory() {
if (entry.getBreakOutCategory() == null) {
return Optional.empty();
}
var cat = DataStorage.get().getStoreCategoryIfPresent(entry.getBreakOutCategory());
if (cat.isEmpty()) {
return Optional.empty();
}
return Optional.of(StoreViewState.get().getCategoryWrapper(cat.get()));
}
public void mergeBreakOutCategory() {
ThreadHelper.runAsync(() -> {
DataStorage.get().mergeBreakOutCategory(entry);
@@ -416,6 +416,10 @@ public class StoreViewState {
return;
}
if (found.get().equals(activeCategory.getValue())) {
activeCategory.setValue(found.get().getParent());
}
synchronized (this) {
categories.getList().remove(found.get());
}
@@ -427,7 +431,7 @@ public class StoreViewState {
}
@Override
public void onEntryCategoryChange(DataStoreCategory from, DataStoreCategory to) {
public void onEntryCategoryChange() {
Platform.runLater(() -> {
synchronized (this) {
categories.getList().forEach(storeCategoryWrapper -> storeCategoryWrapper.update());
@@ -1,6 +1,7 @@
package io.xpipe.app.storage;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.ext.GroupStore;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.ext.NameableStore;
import io.xpipe.app.issue.ErrorEventFactory;
@@ -402,7 +403,12 @@ public abstract class DataStorage {
}
public DataStoreCategory breakOutCategory(DataStoreEntry entry) {
if (!(entry.getStore() instanceof FixedHierarchyStore)) {
if (!(entry.getStore() instanceof FixedHierarchyStore) && !(entry.getStore() instanceof GroupStore<?>)) {
return null;
}
var parent = getDefaultDisplayParent(entry).or(() -> getSyntheticParent(entry));
if (parent.isEmpty()) {
return null;
}
@@ -419,22 +425,46 @@ public abstract class DataStorage {
DataStoreCategoryConfig.empty());
addStoreCategory(breakOut);
entry.setBreakOutCategory(breakOut);
entry.setExpanded(true);
var children = getStoreChildren(entry);
children.forEach(child -> {
child.setCategoryUuid(breakOut.getUuid());
var children = getDeepStoreChildren(entry);
var childrenToKeep = new HashSet<DataStoreEntry>();
children.forEach(c -> {
if (c.getBreakOutCategory() != null) {
childrenToKeep.addAll(getDeepStoreChildren(c));
childrenToKeep.add(c);
}
});
listeners.forEach(storageListener -> storageListener.onEntryCategoryChange(cat, breakOut));
children.forEach(child -> {
if (!childrenToKeep.contains(child)) {
child.setCategoryUuid(breakOut.getUuid());
}
});
entry.setCategoryUuid(breakOut.getUuid());
var categoriesToMove = new ArrayList<DataStoreCategory>();
children.forEach(child -> {
if (child.getBreakOutCategory() != null) {
var childBreakOut = getStoreCategoryIfPresent(child.getBreakOutCategory());
if (childBreakOut.isPresent() && childBreakOut.get().getParentCategory().equals(cat.getUuid())) {
categoriesToMove.add(childBreakOut.get());
}
}
});
categoriesToMove.forEach(toMove -> {
toMove.setParentCategory(breakOut.getUuid());
listeners.forEach(storageListener -> storageListener.onCategoryRemove(toMove));
listeners.forEach(storageListener -> storageListener.onCategoryAdd(toMove));
});
listeners.forEach(storageListener -> storageListener.onEntryCategoryChange());
listeners.forEach(storageListener -> storageListener.onStoreListUpdate());
saveAsync();
return breakOut;
}
public void mergeBreakOutCategory(DataStoreEntry entry) {
if (!(entry.getStore() instanceof FixedHierarchyStore)) {
return;
}
if (entry.getBreakOutCategory() == null) {
return;
}
@@ -445,12 +475,30 @@ public abstract class DataStorage {
return;
}
var parent = getDefaultDisplayParent(entry).or(() -> getSyntheticParent(entry));
if (parent.isEmpty()) {
return;
}
var moveCategories = new ArrayList<DataStoreCategory>();
var children = getStoreChildren(entry);
children.forEach(child -> {
child.setCategoryUuid(entry.getCategoryUuid());
if (child.getBreakOutCategory() == null) {
child.setCategoryUuid(parent.get().getCategoryUuid());
} else {
var cbo = getStoreCategoryIfPresent(child.getBreakOutCategory());
if (cbo.isPresent() && cbo.get().getParentCategory().equals(breakOut.get().getUuid())) {
moveCategories.add(cbo.get());
}
}
});
moveCategories.forEach(mc -> {
mc.setParentCategory(parent.get().getCategoryUuid());
});
entry.setCategoryUuid(parent.get().getCategoryUuid());
listeners.forEach(
storageListener -> storageListener.onEntryCategoryChange(breakOut.get(), getStoreCategory(entry)));
storageListener -> storageListener.onEntryCategoryChange());
deleteStoreCategory(breakOut.get(), false, false);
entry.setBreakOutCategory(null);
listeners.forEach(storageListener -> storageListener.onStoreListUpdate());
@@ -472,7 +520,7 @@ public abstract class DataStorage {
child.setCategoryUuid(newCategory.getUuid());
});
listeners.forEach(storageListener -> storageListener.onEntryCategoryChange(oldCat, newCategory));
listeners.forEach(storageListener -> storageListener.onEntryCategoryChange());
listeners.forEach(storageListener -> storageListener.onStoreListUpdate());
saveAsync();
}
@@ -12,5 +12,5 @@ public interface StorageListener {
void onCategoryRemove(DataStoreCategory category);
void onEntryCategoryChange(DataStoreCategory from, DataStoreCategory to);
void onEntryCategoryChange();
}
@@ -139,7 +139,9 @@ public class IdentitySelectComp extends Comp<CompStructure<HBox>> {
layout.apply(struc -> {
struc.get().focusedProperty().addListener((observable, oldValue, newValue) -> {
struc.get().getChildren().getFirst().requestFocus();
Platform.runLater(() -> {
struc.get().getChildren().getFirst().requestFocus();
});
});
});
@@ -2,7 +2,7 @@ package io.xpipe.ext.base.identity;
import io.xpipe.app.util.*;
import io.xpipe.core.store.*;
import io.xpipe.ext.base.SelfReferentialStore;
import io.xpipe.app.ext.SelfReferentialStore;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@@ -30,28 +30,17 @@ public interface IdentityValue {
}
var found = DataStorage.get().getStoreEntryIfPresent(effective.getDefaultIdentityStore());
if (found.isEmpty() || !(found.get().getStore() instanceof IdentityStore identityStore)) {
if (found.isEmpty() || !(found.get().getStore() instanceof IdentityStore)) {
return null;
}
return new Ref(found.get().ref());
}
static IdentityValue ofCategory(DataStoreEntry e) {
var target = e.getBreakOutCategory() != null
? DataStorage.get()
.getStoreCategoryIfPresent(e.getBreakOutCategory())
.orElse(null)
: null;
if (target == null) {
target = DataStorage.get().getStoreCategory(e);
}
var effective = DataStorage.get().getEffectiveCategoryConfig(target);
if (effective.getDefaultIdentityStore() == null) {
return null;
}
var found = DataStorage.get().getStoreEntryIfPresent(effective.getDefaultIdentityStore());
static IdentityValue ofBreakout(DataStoreEntry e) {
var cat = DataStorage.get().getStoreCategory(e);
var uuid = cat.getConfig().getDefaultIdentityStore();
var found = DataStorage.get().getStoreEntryIfPresent(uuid);
if (found.isEmpty() || !(found.get().getStore() instanceof IdentityStore)) {
return null;
}
@@ -2,8 +2,8 @@ package io.xpipe.ext.base.script;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.ext.base.GroupStore;
import io.xpipe.ext.base.SelfReferentialStore;
import io.xpipe.app.ext.GroupStore;
import io.xpipe.app.ext.SelfReferentialStore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.EqualsAndHashCode;
@@ -7,7 +7,7 @@ import io.xpipe.app.util.Validators;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.util.ValidationException;
import io.xpipe.ext.base.SelfReferentialStore;
import io.xpipe.app.ext.SelfReferentialStore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.EqualsAndHashCode;
@@ -3,7 +3,7 @@ package io.xpipe.ext.base.service;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.Validators;
import io.xpipe.core.store.DataStore;
import io.xpipe.ext.base.GroupStore;
import io.xpipe.app.ext.GroupStore;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
-1
View File
@@ -11,7 +11,6 @@ import io.xpipe.ext.base.store.StoreStartActionProvider;
import io.xpipe.ext.base.store.StoreStopActionProvider;
open module io.xpipe.ext.base {
exports io.xpipe.ext.base;
exports io.xpipe.ext.base.script;
exports io.xpipe.ext.base.store;
exports io.xpipe.ext.base.desktop;
@@ -7,6 +7,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.CommandViewBase;
import io.xpipe.core.process.*;
import io.xpipe.ext.base.identity.IdentityValue;
import lombok.NonNull;
import java.util.*;
@@ -112,7 +113,7 @@ public class IncusCommandView extends CommandViewBase {
return listContainersAndStates().entrySet().stream()
.map(s -> {
boolean running = s.getValue().toLowerCase(Locale.ROOT).equals("running");
var c = new IncusContainerStore(store, s.getKey(), null);
var c = new IncusContainerStore(store, s.getKey(), IdentityValue.ofBreakout(store.get()));
var entry = DataStoreEntry.createNew(c.getContainerName(), c);
entry.setStorePersistentState(ContainerStoreState.builder()
.containerState(s.getValue())
@@ -8,7 +8,7 @@ import io.xpipe.app.util.Validators;
import io.xpipe.core.store.DataStoreState;
import io.xpipe.core.store.FixedChildStore;
import io.xpipe.core.store.StatefulDataStore;
import io.xpipe.ext.base.SelfReferentialStore;
import io.xpipe.app.ext.SelfReferentialStore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.EqualsAndHashCode;
@@ -8,7 +8,7 @@ import io.xpipe.app.util.Validators;
import io.xpipe.core.store.DataStoreState;
import io.xpipe.core.store.FixedChildStore;
import io.xpipe.core.store.StatefulDataStore;
import io.xpipe.ext.base.SelfReferentialStore;
import io.xpipe.app.ext.SelfReferentialStore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.EqualsAndHashCode;
@@ -7,6 +7,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.CommandViewBase;
import io.xpipe.core.process.*;
import io.xpipe.ext.base.identity.IdentityValue;
import lombok.NonNull;
import java.util.*;
@@ -123,6 +124,7 @@ public class LxdCommandView extends CommandViewBase {
var c = LxdContainerStore.builder()
.cmd(store)
.containerName(s.getKey())
.identity(IdentityValue.ofBreakout(store.get()))
.build();
var entry = DataStoreEntry.createNew(c.getContainerName(), c);
entry.setStorePersistentState(ContainerStoreState.builder()
@@ -52,8 +52,8 @@ public class LxdContainerConsoleActionProvider implements HubLeafProvider<LxdCon
@Override
public void executeImpl() throws Exception {
var d = (LxdContainerStore) ref.getStore();
var view = new IncusCommandView(
var d = ref.getStore();
var view = new LxdCommandView(
d.getCmd().getStore().getHost().getStore().getOrStartSession());
TerminalLauncher.open(ref.get().getName(), view.console(d.getContainerName()));
}
@@ -57,8 +57,8 @@ public class LxdContainerEditConfigActionProvider implements HubLeafProvider<Lxd
@Override
public void executeImpl() throws Exception {
var d = (LxdContainerStore) ref.getStore();
var view = new IncusCommandView(
var d = ref.getStore();
var view = new LxdCommandView(
d.getCmd().getStore().getHost().getStore().getOrStartSession());
TerminalLauncher.open(ref.get().getName(), view.configEdit(d.getContainerName()));
}
@@ -60,7 +60,7 @@ public class LxdContainerEditRunConfigActionProvider implements HubLeafProvider<
@Override
public void executeImpl() throws Exception {
var d = (LxdContainerStore) ref.getStore();
var d = ref.getStore();
var elevatedRef = ProcessControlProvider.get()
.elevated(d.getCmd().getStore().getHost().get().ref());
var file = FilePath.of("/run/lxd/" + d.getContainerName() + "/lxc.conf");
@@ -10,7 +10,7 @@ import io.xpipe.app.util.FixedHierarchyStore;
import io.xpipe.app.util.Validators;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.*;
import io.xpipe.ext.base.SelfReferentialStore;
import io.xpipe.app.ext.SelfReferentialStore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.EqualsAndHashCode;
@@ -9,7 +9,7 @@ import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.FixedChildStore;
import io.xpipe.core.store.InternalCacheDataStore;
import io.xpipe.core.store.StatefulDataStore;
import io.xpipe.ext.base.SelfReferentialStore;
import io.xpipe.app.ext.SelfReferentialStore;
import io.xpipe.ext.base.service.AbstractServiceStore;
import io.xpipe.ext.base.service.FixedServiceCreatorStore;
import io.xpipe.ext.base.service.MappedServiceStore;