Преглед изворни кода

revert: remove view-level access control, use existing collection RBAC

Views are tied to collections which already have RBAC permissions.
Remove the duplicate visible_to_groups/editable_by_groups fields from
ViewSettings. The View edit page will be updated to manage collection
and field permissions using the existing RBAC system instead.
Fszontagh пре 6 месеци
родитељ
комит
5e1498dbbc

+ 0 - 2
webserver/include/smartbotic/webserver/view_service.hpp

@@ -58,8 +58,6 @@ struct ViewSettings {
     std::string icon;
     nlohmann::json filters;  // Default filters
     nlohmann::json sort;     // Default sort
-    std::vector<std::string> visible_to_groups;   // Groups that can see this view (empty = all)
-    std::vector<std::string> editable_by_groups;  // Groups that can edit this view (empty = admins only)
 };
 
 /// View information

+ 4 - 42
webserver/src/http_server.cpp

@@ -4072,21 +4072,6 @@ void HttpServer::HandleCreateView(const httplib::Request& req, httplib::Response
             request.settings.icon = settings_json.value("icon", "");
             request.settings.filters = settings_json.value("filters", nlohmann::json::object());
             request.settings.sort = settings_json.value("sort", nlohmann::json::object());
-            // Parse access control arrays
-            if (settings_json.contains("visible_to_groups") && settings_json["visible_to_groups"].is_array()) {
-                for (const auto& group : settings_json["visible_to_groups"]) {
-                    if (group.is_string()) {
-                        request.settings.visible_to_groups.push_back(group.get<std::string>());
-                    }
-                }
-            }
-            if (settings_json.contains("editable_by_groups") && settings_json["editable_by_groups"].is_array()) {
-                for (const auto& group : settings_json["editable_by_groups"]) {
-                    if (group.is_string()) {
-                        request.settings.editable_by_groups.push_back(group.get<std::string>());
-                    }
-                }
-            }
         }
 
         auto result = viewService_->CreateView(request);
@@ -4149,9 +4134,7 @@ void HttpServer::HandleCreateView(const httplib::Request& req, httplib::Response
             {"show_in_sidebar", result.view->settings.show_in_sidebar},
             {"icon", result.view->settings.icon},
             {"filters", result.view->settings.filters},
-            {"sort", result.view->settings.sort},
-            {"visible_to_groups", result.view->settings.visible_to_groups},
-            {"editable_by_groups", result.view->settings.editable_by_groups}
+            {"sort", result.view->settings.sort}
         };
 
         res.status = 201;
@@ -4241,9 +4224,7 @@ void HttpServer::HandleListViews(const httplib::Request& req, httplib::Response&
             view_json["settings"] = {
                 {"is_default", view.settings.is_default},
                 {"show_in_sidebar", view.settings.show_in_sidebar},
-                {"icon", view.settings.icon},
-                {"visible_to_groups", view.settings.visible_to_groups},
-                {"editable_by_groups", view.settings.editable_by_groups}
+                {"icon", view.settings.icon}
             };
 
             views_json.push_back(view_json);
@@ -4359,9 +4340,7 @@ void HttpServer::HandleGetView(const httplib::Request& req, httplib::Response& r
             {"show_in_sidebar", result.view->settings.show_in_sidebar},
             {"icon", result.view->settings.icon},
             {"filters", result.view->settings.filters},
-            {"sort", result.view->settings.sort},
-            {"visible_to_groups", result.view->settings.visible_to_groups},
-            {"editable_by_groups", result.view->settings.editable_by_groups}
+            {"sort", result.view->settings.sort}
         };
 
         res.set_content(view_json.dump(), "application/json");
@@ -4473,21 +4452,6 @@ void HttpServer::HandleUpdateView(const httplib::Request& req, httplib::Response
             settings.icon = settings_json.value("icon", "");
             settings.filters = settings_json.value("filters", nlohmann::json::object());
             settings.sort = settings_json.value("sort", nlohmann::json::object());
-            // Parse access control arrays
-            if (settings_json.contains("visible_to_groups") && settings_json["visible_to_groups"].is_array()) {
-                for (const auto& group : settings_json["visible_to_groups"]) {
-                    if (group.is_string()) {
-                        settings.visible_to_groups.push_back(group.get<std::string>());
-                    }
-                }
-            }
-            if (settings_json.contains("editable_by_groups") && settings_json["editable_by_groups"].is_array()) {
-                for (const auto& group : settings_json["editable_by_groups"]) {
-                    if (group.is_string()) {
-                        settings.editable_by_groups.push_back(group.get<std::string>());
-                    }
-                }
-            }
             request.settings = settings;
         }
 
@@ -4551,9 +4515,7 @@ void HttpServer::HandleUpdateView(const httplib::Request& req, httplib::Response
             {"show_in_sidebar", result.view->settings.show_in_sidebar},
             {"icon", result.view->settings.icon},
             {"filters", result.view->settings.filters},
-            {"sort", result.view->settings.sort},
-            {"visible_to_groups", result.view->settings.visible_to_groups},
-            {"editable_by_groups", result.view->settings.editable_by_groups}
+            {"sort", result.view->settings.sort}
         };
 
         res.set_content(view_json.dump(), "application/json");

+ 1 - 20
webserver/src/view_service.cpp

@@ -555,9 +555,7 @@ auto ViewService::SettingsToJson(const ViewSettings& settings) -> nlohmann::json
         {"show_in_sidebar", settings.show_in_sidebar},
         {"icon", settings.icon},
         {"filters", settings.filters},
-        {"sort", settings.sort},
-        {"visible_to_groups", settings.visible_to_groups},
-        {"editable_by_groups", settings.editable_by_groups}
+        {"sort", settings.sort}
     };
 }
 
@@ -568,23 +566,6 @@ auto ViewService::JsonToSettings(const nlohmann::json& json) -> ViewSettings {
     settings.icon = json.value("icon", "");
     settings.filters = json.value("filters", nlohmann::json::object());
     settings.sort = json.value("sort", nlohmann::json::object());
-
-    // Parse access control arrays
-    if (json.contains("visible_to_groups") && json["visible_to_groups"].is_array()) {
-        for (const auto& group : json["visible_to_groups"]) {
-            if (group.is_string()) {
-                settings.visible_to_groups.push_back(group.get<std::string>());
-            }
-        }
-    }
-    if (json.contains("editable_by_groups") && json["editable_by_groups"].is_array()) {
-        for (const auto& group : json["editable_by_groups"]) {
-            if (group.is_string()) {
-                settings.editable_by_groups.push_back(group.get<std::string>());
-            }
-        }
-    }
-
     return settings;
 }
 

+ 5 - 100
webui/src/pages/Views.tsx

@@ -7,7 +7,6 @@ import apiClient from '@/api/client'
 import { useWorkspace } from '@/contexts/WorkspaceContext'
 import Button from '@/components/Button'
 import Input from '@/components/Input'
-import GroupMultiSelect from '@/components/GroupMultiSelect'
 
 // Field type definitions matching backend
 const FIELD_TYPES = [
@@ -337,17 +336,6 @@ function ViewModal({
   const [isLoading, setIsLoading] = useState(false)
   const [error, setError] = useState<string | null>(null)
 
-  // Auto-create collection state
-  const [autoCreateCollection, setAutoCreateCollection] = useState(false)
-
-  // Access control state
-  const [visibleToGroups, setVisibleToGroups] = useState<string[]>(
-    (view?.settings?.visible_to_groups as string[]) || []
-  )
-  const [editableByGroups, setEditableByGroups] = useState<string[]>(
-    (view?.settings?.editable_by_groups as string[]) || []
-  )
-
   // Local state for field name editing to avoid re-renders
   const [editingFieldId, setEditingFieldId] = useState<string | null>(null)
   const [editingFieldName, setEditingFieldName] = useState('')
@@ -426,13 +414,7 @@ function ViewModal({
       return
     }
 
-    // Use name as collection name if auto-create is enabled
-    let targetCollectionName = collectionName
-    if (autoCreateCollection && !isEditing) {
-      targetCollectionName = name
-    }
-
-    if (!targetCollectionName) {
+    if (!collectionName) {
       setError('Please select a collection')
       return
     }
@@ -441,24 +423,6 @@ function ViewModal({
     setError(null)
 
     try {
-      // Auto-create collection if checkbox is checked
-      if (autoCreateCollection && !isEditing) {
-        try {
-          await apiClient.post(`/workspaces/${workspaceId}/collections`, {
-            name: name,
-            settings: {},
-          })
-        } catch (err) {
-          // Ignore "already exists" error, fail on others
-          const message = err instanceof Error ? err.message : ''
-          if (!message.includes('already exists')) {
-            setError('Failed to create collection: ' + message)
-            setIsLoading(false)
-            return
-          }
-        }
-      }
-
       // Build schema in backend format
       const schemaFields = sortedFields.map((f) => {
         const field: Omit<SchemaField, '_id'> = {
@@ -485,14 +449,10 @@ function ViewModal({
 
       const payload = {
         name,
-        collection_name: targetCollectionName,
+        collection_name: collectionName,
         schema: {
           fields: schemaFields,
         },
-        settings: {
-          visible_to_groups: visibleToGroups,
-          editable_by_groups: editableByGroups,
-        },
       }
 
       if (isEditing && view) {
@@ -552,11 +512,11 @@ function ViewModal({
                   <span className="ml-1 text-red-500">*</span>
                 </label>
                 <select
-                  value={autoCreateCollection ? name : collectionName}
+                  value={collectionName}
                   onChange={(e) => setCollectionName(e.target.value)}
                   className="w-full rounded-lg border border-gray-300 px-3 py-2"
-                  required={!autoCreateCollection}
-                  disabled={isEditing || autoCreateCollection}
+                  required
+                  disabled={isEditing}
                 >
                   <option value="">Select a collection...</option>
                   {collections
@@ -567,26 +527,6 @@ function ViewModal({
                       </option>
                     ))}
                 </select>
-                {/* Auto-create collection checkbox */}
-                {!isEditing && (
-                  <div className="mt-2 flex items-center gap-2">
-                    <input
-                      type="checkbox"
-                      id="auto-create-collection"
-                      checked={autoCreateCollection}
-                      onChange={(e) => {
-                        setAutoCreateCollection(e.target.checked)
-                        if (e.target.checked) {
-                          setCollectionName(name)
-                        }
-                      }}
-                      className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
-                    />
-                    <label htmlFor="auto-create-collection" className="text-sm text-gray-700">
-                      Create new collection with same name
-                    </label>
-                  </div>
-                )}
               </div>
             </div>
 
@@ -669,41 +609,6 @@ function ViewModal({
                 </div>
               )}
             </div>
-
-            {/* Access Control Section */}
-            <div className="mt-6 border-t pt-6">
-              <h3 className="mb-4 text-lg font-medium text-gray-900">Access Control</h3>
-
-              <div className="space-y-4">
-                <div>
-                  <label className="mb-2 block text-sm font-medium text-gray-700">
-                    Visible To
-                  </label>
-                  <p className="mb-2 text-xs text-gray-500">
-                    Select groups that can see this view. Leave empty for all users.
-                  </p>
-                  <GroupMultiSelect
-                    workspaceId={workspaceId}
-                    selectedGroups={visibleToGroups}
-                    onChange={setVisibleToGroups}
-                  />
-                </div>
-
-                <div>
-                  <label className="mb-2 block text-sm font-medium text-gray-700">
-                    Editable By
-                  </label>
-                  <p className="mb-2 text-xs text-gray-500">
-                    Select groups that can modify this view. Leave empty for workspace admins only.
-                  </p>
-                  <GroupMultiSelect
-                    workspaceId={workspaceId}
-                    selectedGroups={editableByGroups}
-                    onChange={setEditableByGroups}
-                  />
-                </div>
-              </div>
-            </div>
           </div>
 
           <div className="sticky bottom-0 flex justify-end gap-3 border-t bg-gray-50 px-6 py-4">