Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mesheryctl for openSUSE:Factory checked in at 2025-11-27 15:20:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mesheryctl (Old) and /work/SRC/openSUSE:Factory/.mesheryctl.new.14147 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mesheryctl" Thu Nov 27 15:20:48 2025 rev:139 rq:1320283 version:0.8.176 Changes: -------- --- /work/SRC/openSUSE:Factory/mesheryctl/mesheryctl.changes 2025-11-25 16:58:33.932375239 +0100 +++ /work/SRC/openSUSE:Factory/.mesheryctl.new.14147/mesheryctl.changes 2025-11-27 15:22:18.878886324 +0100 @@ -1,0 +2,16 @@ +Thu Nov 27 06:05:20 UTC 2025 - Johannes Kastl <[email protected]> + +- update to 0.8.176: + no CLI-related changes +- update to 0.8.175: + * General + - Revert "[server] Add workspace_id and organization_id to GET + /api/pattern/{id} endpoint" @aabidsofi19 (#16505) + * Meshery CLI + - chore: remove stale TODO from auth.go @parthivsaikia (#16495) +- update to 0.8.174: + * General + - [server] Add workspace_id and organization_id to GET + /api/pattern/{id} endpoint @copilot-swe-agent (#16500) + +------------------------------------------------------------------- Old: ---- mesheryctl-0.8.173.obscpio New: ---- mesheryctl-0.8.176.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mesheryctl.spec ++++++ --- /var/tmp/diff_new_pack.zrsztj/_old 2025-11-27 15:22:22.491038655 +0100 +++ /var/tmp/diff_new_pack.zrsztj/_new 2025-11-27 15:22:22.495038824 +0100 @@ -17,7 +17,7 @@ Name: mesheryctl -Version: 0.8.173 +Version: 0.8.176 Release: 0 Summary: CLI for the meshery cloud native management plane License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.zrsztj/_old 2025-11-27 15:22:22.535040511 +0100 +++ /var/tmp/diff_new_pack.zrsztj/_new 2025-11-27 15:22:22.539040679 +0100 @@ -5,7 +5,7 @@ <param name="exclude">.git</param> <param name="exclude">docs/*</param> <param name="exclude">server/meshmodel/*</param> - <param name="revision">v0.8.173</param> + <param name="revision">v0.8.176</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">disable</param> ++++++ mesheryctl-0.8.173.obscpio -> mesheryctl-0.8.176.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/install/samples/provider_capabilities.json new/mesheryctl-0.8.176/install/samples/provider_capabilities.json --- old/mesheryctl-0.8.173/install/samples/provider_capabilities.json 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/install/samples/provider_capabilities.json 2025-11-26 09:08:39.000000000 +0100 @@ -204,6 +204,10 @@ "endpoint": "/api/identity/users/anonymous" } ], + "redirects": { + "/": "/extension/meshmap", + "": "/extension/meshmap" + }, "restrictedAccess": { "isMesheryUiRestricted": true, "allowedComponents": { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/mesheryctl/pkg/utils/auth.go new/mesheryctl-0.8.176/mesheryctl/pkg/utils/auth.go --- old/mesheryctl-0.8.173/mesheryctl/pkg/utils/auth.go 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/mesheryctl/pkg/utils/auth.go 2025-11-26 09:08:39.000000000 +0100 @@ -176,7 +176,6 @@ return ErrLoadConfig(err) } - // TODO: get this from the global config req, err := http.NewRequest("GET", mctlCfg.GetBaseMesheryURL()+"/api/user/token", bytes.NewBuffer([]byte(""))) if err != nil { err = errors.Wrap(err, "error Creating the request: ") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/server/handlers/ui_handler.go new/mesheryctl-0.8.176/server/handlers/ui_handler.go --- old/mesheryctl-0.8.173/server/handlers/ui_handler.go 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/server/handlers/ui_handler.go 2025-11-26 09:08:39.000000000 +0100 @@ -5,9 +5,6 @@ "net/http" "path/filepath" "strings" - - "github.com/meshery/meshery/server/models" - "github.com/spf13/viper" ) var dynamicUIEndpoints = map[string]string{ @@ -47,21 +44,13 @@ reqURL := r.URL.Path reqURL = strings.Replace(reqURL, reqBasePath, "", 1) var filePath strings.Builder - if reqURL == "/" && viper.Get("RELEASE_CHANNEL") == (models.Kanvas{}).String() { - provider, ok := h.config.Providers[h.Provider] - if ok && provider != nil { - provProps := provider.GetProviderProperties() - if len(provProps.Extensions.Navigator) <= 0 { - // For the case when the token is valid but the extension capability is missing in provider. - // This was the cause for circular redirects. - releaseChannel := models.NewReleaseChannelInterceptor(viper.GetString("RELEASE_CHANNEL"), provider, h.log) - if releaseChannel != nil { - releaseChannel.Intercept(r, w) - return - } - } - redirectURL := models.GetRedirectURLForNavigatorExtension(&provProps, h.log) - http.Redirect(w, r, redirectURL, http.StatusPermanentRedirect) + + provider, ok := h.config.Providers[h.Provider] + if ok && provider != nil { + redirect, hasRedirect := provider.GetProviderProperties().Redirects[reqURL] + + if hasRedirect { + http.Redirect(w, r, redirect, http.StatusPermanentRedirect) return } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/server/models/meshery_pattern.go new/mesheryctl-0.8.176/server/models/meshery_pattern.go --- old/mesheryctl-0.8.173/server/models/meshery_pattern.go 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/server/models/meshery_pattern.go 2025-11-26 09:08:39.000000000 +0100 @@ -101,11 +101,13 @@ UpdatedAt *time.Time `json:"updated_at,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` - ViewCount int `json:"view_count" db:"view_count"` - ShareCount int `json:"share_count" db:"share_count"` - DownloadCount int `json:"download_count" db:"download_count"` - CloneCount int `json:"clone_count" db:"clone_count"` - DeploymentCount int `json:"deployment_count" db:"deployment_count"` + ViewCount int `json:"view_count" db:"view_count"` + ShareCount int `json:"share_count" db:"share_count"` + DownloadCount int `json:"download_count" db:"download_count"` + CloneCount int `json:"clone_count" db:"clone_count"` + DeploymentCount int `json:"deployment_count" db:"deployment_count"` + WorkspaceID uuid.UUID `json:"workspace_id,omitempty" db:"-"` + OrgID uuid.UUID `json:"org_id,omitempty" db:"-"` } // MesheryCatalogPatternRequestBody refers to the type of request body diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/server/models/providers.go new/mesheryctl-0.8.176/server/models/providers.go --- old/mesheryctl-0.8.173/server/models/providers.go 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/server/models/providers.go 2025-11-26 09:08:39.000000000 +0100 @@ -42,15 +42,16 @@ // ProviderProperties represents the structure of properties that a provider has type ProviderProperties struct { - ProviderType ProviderType `json:"provider_type,omitempty"` - PackageVersion string `json:"package_version,omitempty"` - PackageURL string `json:"package_url,omitempty"` - ProviderName string `json:"provider_name,omitempty"` - ProviderDescription []string `json:"provider_description,omitempty"` - ProviderURL string `json:"provider_url,omitempty"` - Extensions Extensions `json:"extensions,omitempty"` - Capabilities Capabilities `json:"capabilities,omitempty"` - RestrictedAccess RestrictedAccess `json:"restrictedAccess,omitempty"` + ProviderType ProviderType `json:"provider_type,omitempty"` + PackageVersion string `json:"package_version,omitempty"` + PackageURL string `json:"package_url,omitempty"` + ProviderName string `json:"provider_name,omitempty"` + ProviderDescription []string `json:"provider_description,omitempty"` + ProviderURL string `json:"provider_url,omitempty"` + Extensions Extensions `json:"extensions,omitempty"` + Capabilities Capabilities `json:"capabilities,omitempty"` + RestrictedAccess RestrictedAccess `json:"restrictedAccess,omitempty"` + Redirects map[string]string `json:"redirects,omitempty"` } type Adapters struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/server/models/release_channel.go new/mesheryctl-0.8.176/server/models/release_channel.go --- old/mesheryctl-0.8.173/server/models/release_channel.go 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/server/models/release_channel.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,175 +0,0 @@ -package models - -import ( - "bytes" - "encoding/json" - "net/http" - "net/url" - "strings" - - "github.com/gofrs/uuid" - "github.com/meshery/meshery/server/core" - "github.com/meshery/meshery/server/models/connections" - "github.com/meshery/meshkit/encoding" - "github.com/meshery/meshkit/logger" - "github.com/pkg/errors" -) - -type ReleaseChannel interface { - Intercept(req *http.Request, res http.ResponseWriter) -} - -type Default struct{} - -func (Default) Intercept(req *http.Request, res http.ResponseWriter) {} - -func NewReleaseChannelInterceptor(channel string, provider Provider, log logger.Handler) ReleaseChannel { - stable := &Stable{} - edge := &Edge{} - kanvas := &Kanvas{Provider: provider, log: log} - - switch channel { - case kanvas.String(): - return kanvas - case stable.String(): - fallthrough - case edge.String(): - fallthrough - default: - return nil - } -} - -type Stable struct{ Default } - -func (Stable) String() string { - return "stable" -} - -type Edge struct{ Default } - -func (*Edge) String() string { - return "edge" -} - -type Kanvas struct { - Provider Provider - log logger.Handler -} - -func (Kanvas) String() string { - return "kanvas" -} - -type AnonymousFlowResponse struct { - AccessToken string `json:"access_token"` - Capabilities ProviderProperties `json:"capability,omitempty"` - UserID uuid.UUID `json:"user_id,omitempty"` -} - -// This function is triggered when the token is invalid, the channel is in Kanvas mode, or when a token is present but the capabilities lack the required extension. -// Process flow: -// 1. Retrieve the capabilities of the anonymous user. -// 2. Construct the connection payload. -// 3. Generate the user using the special token. -// 4. If the navigator is missing, prompt the user to download the navigator extension. - -// The appearance of the default /error page on the Kanvas site could be due to one of the following reasons: -// 1. The remote provider is down, causing an error while fetching capabilities. -// 2. The provided special token is either empty or incorrect, resulting in an unauthorized error. -// 3. An issue occurred during the download of the extension package. - -// For exact diagnostics, check the server logs in case of any of these errors. - -func (k *Kanvas) Intercept(req *http.Request, res http.ResponseWriter) { - providerProperties := k.Provider.GetProviderProperties() - providerURL, _ := url.Parse(k.Provider.GetProviderURL()) - errorUI := "/error" - ep, exists := providerProperties.Capabilities.GetEndpointForFeature(PersistAnonymousUser) - - if !exists { - err := ErrInvalidCapability("PersistAnonymousUser", k.Provider.Name()) - k.log.Error(err) - http.Redirect(res, req, errorUI, http.StatusFound) - return - } - - credential := make(map[string]interface{}, 0) - connectionPayload := connections.BuildMesheryConnectionPayload(req.Context().Value(MesheryServerURL).(string), credential) - - providerURL = providerURL.JoinPath(ep) - - buf, _ := encoding.Marshal(connectionPayload) - data := bytes.NewReader(buf) - - client := &http.Client{} - newReq, _ := http.NewRequest("POST", providerURL.String(), data) - - newReq.Header.Set("X-API-Key", GlobalTokenForAnonymousResults) - - resp, err := client.Do(newReq) - if err != nil { - err = ErrUnreachableRemoteProvider(err) - k.log.Error(err) - http.Redirect(res, req, errorUI, http.StatusFound) - return - } - defer resp.Body.Close() - - flowResponse := AnonymousFlowResponse{} - err = json.NewDecoder(resp.Body).Decode(&flowResponse) - if err != nil { - err = ErrUnmarshal(err, "user flow response") - k.log.Error(err) - http.Redirect(res, req, errorUI, http.StatusFound) - return - } - - k.Provider.SetJWTCookie(res, flowResponse.AccessToken) - flowResponse.Capabilities.ProviderURL = k.Provider.GetProviderURL() - - err = k.Provider.WriteCapabilitiesForUser(flowResponse.UserID.String(), &flowResponse.Capabilities) - if err != nil { - err = ErrDBPut(errors.Wrapf(err, "failed to write capabilities for the user %s", flowResponse.UserID.String())) - k.log.Error(err) - http.Redirect(res, req, errorUI, http.StatusFound) - - return - } - k.Provider.SetProviderProperties(flowResponse.Capabilities) - // Download the package for the user only if they have extension capability - // The download is skipped if package already exists. - if len(flowResponse.Capabilities.Extensions.Navigator) > 0 { - flowResponse.Capabilities.DownloadProviderExtensionPackage(k.log) - } - redirectURL := GetRedirectURLForNavigatorExtension(&providerProperties, k.log) - - k.log.Infof("Redirecting after intercept base redirect url: %s , interceptedRequestURI %s ", redirectURL, req.URL.String()) - - // if request was directly intercepted from the kanvas page ( /extension ) , then the ref might not be present - // so we can directly redirect back to intercepted page - if strings.HasPrefix(req.URL.Path, "/extension") { - // redirect to the intercepted page with all original query params - k.log.Infof("Redirecting to intercepted page with query params %s", req.URL.RawQuery) - http.Redirect(res, req, req.URL.String(), http.StatusFound) - return - } - // Respect the referrer , and the query params -// The 'ref' query parameter is a base64 encoded URL of the original page the user was on. -// It is used to redirect the user back to that page after a successful login. - // if the ref points to some page other than under /extension then skip ref - refUrl, err := core.GetRefURLFromRequest(req) - k.log.Infof("Referrer URL: %s , %v", refUrl, err) - if strings.HasPrefix(refUrl, "/extension") { - k.log.Infof("Redirecting to referrer %s", refUrl) - http.Redirect(res, req, refUrl, http.StatusFound) - return - } - - if redirectURL == "/" { - k.log.Info("No navigator extension found, redirecting to /error") - redirectURL = errorUI - } - k.log.Infof("No source refs resolved , Redirecting to base kanvas page %s", redirectURL) - http.Redirect(res, req, redirectURL, http.StatusFound) -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/server/models/remote_provider.go new/mesheryctl-0.8.176/server/models/remote_provider.go --- old/mesheryctl-0.8.173/server/models/remote_provider.go 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/server/models/remote_provider.go 2025-11-26 09:08:39.000000000 +0100 @@ -24,8 +24,10 @@ "github.com/gofrs/uuid" SMP "github.com/layer5io/service-mesh-performance/spec" + "github.com/meshery/meshery/server/core" "github.com/meshery/meshery/server/models/connections" "github.com/meshery/meshkit/database" + "github.com/meshery/meshkit/encoding" "github.com/meshery/meshkit/logger" "github.com/meshery/meshkit/models/events" mesherykube "github.com/meshery/meshkit/utils/kubernetes" @@ -74,6 +76,10 @@ MeshsyncDefaultDeploymentMode schemasConnection.MeshsyncDeploymentMode } +type AnonymousFlowResponse struct { + AccessToken string `json:"access_token"` + UserID uuid.UUID `json:"user_id,omitempty"` +} type userSession struct { token string @@ -113,8 +119,7 @@ func (l *RemoteProvider) loadCapabilitiesFromLocalFile(filePath string) (ProviderProperties, error) { - - l.Log.Info("Loading provider capabilities from local file: ", filePath) + l.Log.Info("Loading provider capabilities from local file: ", filePath) file, err := os.Open(filePath) if err != nil { @@ -376,10 +381,99 @@ } } +func (l *RemoteProvider) InterceptLoginAndInitiateAnonymousUserSession(req *http.Request, res http.ResponseWriter) { + providerProperties := l.GetProviderProperties() + providerURL, _ := url.Parse(l.GetProviderURL()) + errorUI := "/error" + ep, exists := providerProperties.Capabilities.GetEndpointForFeature(PersistAnonymousUser) + + if !exists { + err := ErrInvalidCapability("PersistAnonymousUser", l.Name()) + l.Log.Error(err) + http.Redirect(res, req, errorUI, http.StatusFound) + return + } + + credential := make(map[string]interface{}, 0) + connectionPayload := connections.BuildMesheryConnectionPayload(req.Context().Value(MesheryServerURL).(string), credential) + + anonnymouseUserEp := providerURL.JoinPath(ep) + + buf, _ := encoding.Marshal(connectionPayload) + data := bytes.NewReader(buf) + + client := &http.Client{} + newReq, _ := http.NewRequest("POST", anonnymouseUserEp.String(), data) + + newReq.Header.Set("X-API-Key", GlobalTokenForAnonymousResults) + + resp, err := client.Do(newReq) + if err != nil { + err = ErrUnreachableRemoteProvider(err) + l.Log.Error(err) + http.Redirect(res, req, errorUI, http.StatusFound) + return + } + defer resp.Body.Close() + + flowResponse := AnonymousFlowResponse{} + err = json.NewDecoder(resp.Body).Decode(&flowResponse) + if err != nil { + err = ErrUnmarshal(err, "user flow response") + l.Log.Error(err) + http.Redirect(res, req, errorUI, http.StatusFound) + return + } + + l.SetJWTCookie(res, flowResponse.AccessToken) + + err = l.WriteCapabilitiesForUser(flowResponse.UserID.String(), &providerProperties) + if err != nil { + err = ErrDBPut(fmt.Errorf("failed to write capabilities for the user %s: %w", flowResponse.UserID.String(), err)) + l.Log.Error(err) + http.Redirect(res, req, errorUI, http.StatusFound) + + return + } + + redirectURL := GetRedirectURLForNavigatorExtension(&providerProperties, l.Log) + + l.Log.Infof("Redirecting after intercept base redirect url: %s , interceptedRequestURI %s ", redirectURL, req.URL.String()) + + // if request was directly intercepted from the kanvas page ( /extension ) , then the ref might not be present + // so we can directly redirect back to intercepted page + if strings.HasPrefix(req.URL.Path, "/extension") { + // redirect to the intercepted page with all original query params + l.Log.Infof("Redirecting to intercepted page with query params %s", req.URL.RawQuery) + http.Redirect(res, req, req.URL.String(), http.StatusFound) + return + } + // Respect the referrer , and the query params + // The 'ref' query parameter is a base64 encoded URL of the original page the user was on. + // It is used to redirect the user back to that page after a successful login. + // if the ref points to some page other than under /extension then skip ref + refUrl, err := core.GetRefURLFromRequest(req) + l.Log.Infof("Referrer URL: %s , %v", refUrl, err) + if strings.HasPrefix(refUrl, "/extension") { + l.Log.Infof("Redirecting to referrer %s", refUrl) + http.Redirect(res, req, refUrl, http.StatusFound) + return + } + + if redirectURL == "/" { + l.Log.Info("No navigator extension found, redirecting to /error") + redirectURL = errorUI + } + l.Log.Infof("No source refs resolved , Redirecting to base kanvas page %s", redirectURL) + http.Redirect(res, req, redirectURL, http.StatusFound) +} + // InitiateLogin - initiates login flow and returns a true to indicate the handler to "return" or false to continue // // Every Remote Provider must offer this function func (l *RemoteProvider) InitiateLogin(w http.ResponseWriter, r *http.Request, _ bool) { + + _, supportsAnonymousUserSessions := l.GetProviderProperties().Capabilities.GetEndpointForFeature(PersistAnonymousUser) baseCallbackURL := r.Context().Value(MesheryServerCallbackURL).(string) // Support for deep-link and redirection to land user on their originally requested page post authentication instead of dropping user on the root (home) page. @@ -416,11 +510,11 @@ "ref": refURL, } - releaseChannel := NewReleaseChannelInterceptor(viper.GetString("RELEASE_CHANNEL"), l, l.Log) - if releaseChannel != nil { - releaseChannel.Intercept(r, w) + if supportsAnonymousUserSessions { + l.InterceptLoginAndInitiateAnonymousUserSession(r, w) return } + w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0") w.Header().Set("Pragma", "no-cache") w.Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 GMT") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/ui/components/NavigatorExtension.js new/mesheryctl-0.8.176/ui/components/NavigatorExtension.js --- old/mesheryctl-0.8.173/ui/components/NavigatorExtension.js 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/ui/components/NavigatorExtension.js 2025-11-26 09:08:39.000000000 +0100 @@ -46,7 +46,7 @@ const { selectedK8sContexts } = useSelector((state) => state.ui); const [loading, err, RemoteComponent] = useRemoteComponent(url); const { organization: currentOrganization } = useSelector((state) => state.ui); - const { openModalWithDefault } = useContext(WorkspaceModalContext); + const { openModalWithDefault, onLoadResource } = useContext(WorkspaceModalContext); const registryModal = useRegistryModal(); if (err != null) { return ( @@ -127,6 +127,7 @@ currentOrganization, openWorkspaceModal: openModalWithDefault, openRegistryModal: registryModal, + SetCurrentLoadedResourceInOrgWorkspaceSession: onLoadResource, }} /> </DynamicFullScrrenLoader> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/ui/components/SpacesSwitcher/SpaceSwitcher.js new/mesheryctl-0.8.176/ui/components/SpacesSwitcher/SpaceSwitcher.js --- old/mesheryctl-0.8.173/ui/components/SpacesSwitcher/SpaceSwitcher.js 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/ui/components/SpacesSwitcher/SpaceSwitcher.js 2025-11-26 09:08:39.000000000 +0100 @@ -145,7 +145,12 @@ const theme = useTheme(); const isSmallScreen = useMediaQuery('(max-width:400px)'); - const { selectedOrganization } = useGetSelectedOrganization(); + const { selectedOrganization: selectedOrgFromPref } = useGetSelectedOrganization(); + const { currentLoadedResource } = useContext(WorkspaceModalContext); + + const selectedOrganization = currentLoadedResource?.org?.id + ? currentLoadedResource.org + : selectedOrgFromPref; const [updateSelectedOrg, { isLoading: isUpdatingOrg }] = useUpdateSelectedOrganizationMutation(); @@ -200,6 +205,9 @@ : theme.palette.background.constant.white, }, }} + renderValue={() => { + return <span>{selectedOrganization?.name || 'Private Org'}</span>; + }} MenuProps={{ anchorOrigin: { vertical: 'bottom', @@ -223,7 +231,7 @@ className="OrgClass" style={{ marginRight: '1rem', color: theme.palette.icon.default }} /> - <span>{org.name}</span> + <span>{org.name || 'Private Org'}</span> </StyledMenuItem> ))} </StyledSelect> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/ui/components/SpacesSwitcher/WorkspaceSwitcher.js new/mesheryctl-0.8.176/ui/components/SpacesSwitcher/WorkspaceSwitcher.js --- old/mesheryctl-0.8.173/ui/components/SpacesSwitcher/WorkspaceSwitcher.js 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/ui/components/SpacesSwitcher/WorkspaceSwitcher.js 2025-11-26 09:08:39.000000000 +0100 @@ -51,22 +51,25 @@ function WorkspaceSwitcher({ open, fromMobileView }) { const { selectedOrganization } = useGetSelectedOrganization(); const { - selectedWorkspace, + selectedWorkspace: selectedWorkspacePref, allWorkspaces, error: workspaceError, isLoading: isLoadingWorkspaces, } = useGetSelectedWorkspace(); - const isSmallScreen = useMediaQuery('(max-width:400px)'); - const theme = useTheme(); - - const [updateSelectedWorkspace, { isLoading: isUpdatingSelectedWorkspace }] = - useUpdateSelectedWorkspaceMutation(); - const { setSelectedWorkspace, openModal: openWorkspaceModal, setCreateNewWorkspaceModalOpen, + currentLoadedResource, } = useContext(WorkspaceModalContext); + const isSmallScreen = useMediaQuery('(max-width:400px)'); + const theme = useTheme(); + const selectedWorkspace = currentLoadedResource?.workspace?.id + ? currentLoadedResource.workspace + : selectedWorkspacePref; + + const [updateSelectedWorkspace, { isLoading: isUpdatingSelectedWorkspace }] = + useUpdateSelectedWorkspaceMutation(); // useEffect(() => { // if (selectedWorkspace?.id) { @@ -135,7 +138,7 @@ color: fromMobileView ? theme.palette.text.default : undefined, }} > - {selectedWorkspace?.name || ''} + {selectedWorkspace?.name || 'Private Workspace'} </span> ); }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/ui/rtk-query/organization.js new/mesheryctl-0.8.176/ui/rtk-query/organization.js --- old/mesheryctl-0.8.173/ui/rtk-query/organization.js 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/ui/rtk-query/organization.js 2025-11-26 09:08:39.000000000 +0100 @@ -11,6 +11,7 @@ .injectEndpoints({ endpoints: (builder) => ({ getOrgs: builder.query({ + keepUnusedDataFor: 0, query: (queryArgs) => ({ url: `identity/orgs`, params: { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/ui/rtk-query/user.js new/mesheryctl-0.8.176/ui/rtk-query/user.js --- old/mesheryctl-0.8.173/ui/rtk-query/user.js 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/ui/rtk-query/user.js 2025-11-26 09:08:39.000000000 +0100 @@ -327,6 +327,7 @@ return { selectedOrganization, + allOrganizations: allOrgs?.organizations || [], didFallback: !existingSelectedOrganization, isLoading: isLoadingUserPrefs || isLoadingAllOrgs, isError: errorLoadingUserPrefs || errorLoadingAllOrgs, @@ -369,27 +370,6 @@ const didFallback = !existingSelectedWorkspace; - // Update the selected workspace in user preferences if it was not set before - // useEffect(() => { - // if (!isLoadingPrefs && didFallback && selectedWorkspaceID) { - // console.log( - // '[getCurrentWorkspace] setting default workspace', - // selectedWorkspaceID, - // selectedOrganization?.id, - // ); - // updateSelectedWorkspace({ - // orgId: selectedOrganization?.id, - // workspaceId: selectedWorkspaceID, - // }); - // } - // }, [ - // isLoadingPrefs, - // didFallback, - // selectedOrganization?.id, - // selectedWorkspaceID, - // updateSelectedWorkspace, - // ]); - return { selectedWorkspace, didFallback, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/ui/rtk-query/workspace.js new/mesheryctl-0.8.176/ui/rtk-query/workspace.js --- old/mesheryctl-0.8.173/ui/rtk-query/workspace.js 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/ui/rtk-query/workspace.js 2025-11-26 09:08:39.000000000 +0100 @@ -17,6 +17,7 @@ .injectEndpoints({ endpoints: (builder) => ({ getWorkspaces: builder.query({ + keepUnusedDataFor: 0, queryFn: async (queryArgs, { dispatch }, _extraOptions, baseQuery) => { const { expandInfo, ...otherArgs } = queryArgs; const params = urlEncodeParams(otherArgs); @@ -327,6 +328,7 @@ export const { useGetWorkspacesQuery, + useLazyGetWorkspacesQuery, useCreateWorkspaceMutation, useUpdateWorkspaceMutation, useDeleteWorkspaceMutation, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mesheryctl-0.8.173/ui/utils/context/WorkspaceModalContextProvider.js new/mesheryctl-0.8.176/ui/utils/context/WorkspaceModalContextProvider.js --- old/mesheryctl-0.8.173/ui/utils/context/WorkspaceModalContextProvider.js 2025-11-24 18:50:42.000000000 +0100 +++ new/mesheryctl-0.8.176/ui/utils/context/WorkspaceModalContextProvider.js 2025-11-26 09:08:39.000000000 +0100 @@ -1,4 +1,8 @@ import React, { useState } from 'react'; +import { useEffect } from 'react'; +import { mesheryEventBus } from '../eventBus'; +import { useGetSelectedOrganization } from '@/rtk-query/user'; +import { useLazyGetWorkspacesQuery } from '@/rtk-query/workspace'; export const WorkspaceModalContext = React.createContext({ open: false, @@ -11,13 +15,73 @@ setMultiSelectedContent: () => {}, createNewWorkspaceModalOpen: false, setCreateNewWorkspaceModalOpen: () => {}, + currentLoadedResource: { + id: '', + org: { + id: '', + name: '', + }, + workspace: { + id: '', + name: '', + }, + }, + onLoadResource: ({ id, workspaceId, orgId }) => {}, }); const WorkspaceModalContextProvider = ({ children }) => { + const { selectedOrganization, allOrganizations } = useGetSelectedOrganization(); + const [getWorkspaces] = useLazyGetWorkspacesQuery(); const [workspaceModal, setWorkspaceModal] = useState(false); const [selectedWorkspace, setSelectedWorkspace] = useState({ id: '', name: '' }); const [multiSelectedContent, setMultiSelectedContent] = useState([]); const [createNewWorkspaceModalOpen, setCreateNewWorkspaceModalOpen] = useState(false); + // stores the context for currently loaded resource . sometime a user might be viewing a resource + // from differnt org/workpace than the currently selected one + const [currentLoadedResource, setCurrentLoadedResource] = useState({ + id: '', + org: { + id: '', + name: '', + }, + workspace: { + id: '', + name: '', + }, + }); + + const onLoadResource = async ({ id, workspaceId, orgId }) => { + if (!workspaceId && !orgId) { + setCurrentLoadedResource({ id, workspace: { id: '' }, org: { id: '' } }); + return; + } + + try { + const resource = { + id, + workspace: { id: workspaceId, name: 'Private Workspace' }, + org: { id: orgId, name: 'Private Org' }, + }; + const org = allOrganizations.find((o) => o.id == orgId); + console.log('onload resource invoked', workspaceId, orgId, org, allOrganizations); + if (org) { + resource.org = org; + const workspaces = await getWorkspaces({ + page: 0, + pagesize: 'all', + orgID: orgId, + }).unwrap(); + const workspace = (workspaces?.workspaces ?? []).find((w) => w.id == workspaceId); + if (workspace) { + resource.workspace = workspace; + } + } + console.log('onloadResource', workspaceId, orgId, resource); + setCurrentLoadedResource(resource); + } catch (e) { + console.log('[onLoadResource] failed set orgWorkspace context', e); + } + }; return ( <WorkspaceModalContext.Provider @@ -40,7 +104,8 @@ }, multiSelectedContent, setMultiSelectedContent, - + currentLoadedResource, + onLoadResource, createNewWorkspaceModalOpen, setCreateNewWorkspaceModalOpen, }} ++++++ mesheryctl.obsinfo ++++++ --- /var/tmp/diff_new_pack.zrsztj/_old 2025-11-27 15:22:27.163235690 +0100 +++ /var/tmp/diff_new_pack.zrsztj/_new 2025-11-27 15:22:27.183236534 +0100 @@ -1,5 +1,5 @@ name: mesheryctl -version: 0.8.173 -mtime: 1764006642 -commit: 2345459378fa7c24f4e44afc37eedf283df6dbdc +version: 0.8.176 +mtime: 1764144519 +commit: 8e53f3df33a0e2963c7771798c4e561f7fd95f42 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/mesheryctl/vendor.tar.gz /work/SRC/openSUSE:Factory/.mesheryctl.new.14147/vendor.tar.gz differ: char 13, line 1
