diff --git a/ProcessMaker/Observers/UserObserver.php b/ProcessMaker/Observers/UserObserver.php index d8e45ef942..39fcfe1f4f 100644 --- a/ProcessMaker/Observers/UserObserver.php +++ b/ProcessMaker/Observers/UserObserver.php @@ -38,6 +38,11 @@ public function created(User $user): void $perList = [ 'view-process-catalog', 'view-my_requests', + 'overview-tab-task', + 'summary-tab-task', + 'completed-tab-task', + 'form-tab-task', + 'files-tab-task', ]; $permissionIds = Permission::whereIn('name', $perList)->pluck('id')->toArray(); $user->permissions()->attach($permissionIds); diff --git a/database/migrations/2026_05_04_191751_add_permissions_tab_task.php b/database/migrations/2026_05_04_191751_add_permissions_tab_task.php new file mode 100644 index 0000000000..c30dc8262d --- /dev/null +++ b/database/migrations/2026_05_04_191751_add_permissions_tab_task.php @@ -0,0 +1,36 @@ + 'Task tabs', + 'title' => $permission[0], + 'name' => $permission[1], + ]); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Permission::where('group', 'Task tabs')->delete(); + } +}; diff --git a/database/migrations/2026_05_07_142346_add_permissions_tab_task_to_users.php b/database/migrations/2026_05_07_142346_add_permissions_tab_task_to_users.php new file mode 100644 index 0000000000..1174327d8b --- /dev/null +++ b/database/migrations/2026_05_07_142346_add_permissions_tab_task_to_users.php @@ -0,0 +1,82 @@ +whereIn('name', self::TAB_TASK_PERMISSIONS) + ->pluck('id', 'name') + ->values(); + + foreach ($permissionIds as $permissionId) { + $this->assignPermissionToUsers((int) $permissionId); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $permissionIds = DB::table('permissions') + ->whereIn('name', self::TAB_TASK_PERMISSIONS) + ->pluck('id', 'name') + ->values(); + + DB::table('assignables') + ->whereIn('permission_id', $permissionIds) + ->where('assignable_type', User::class) + ->delete(); + } + + private function assignPermissionToUsers(int $permissionId): void + { + $lastUserId = 0; + + do { + $users = DB::table('users AS u') + ->leftJoin('assignables AS a', function ($join) use ($permissionId) { + $join->on('u.id', '=', 'a.assignable_id') + ->where('a.assignable_type', User::class) + ->where('a.permission_id', $permissionId); + }) + ->whereNull('a.permission_id') + ->where('u.id', '>', $lastUserId) + ->where('u.is_administrator', false) + ->select('u.id') + ->orderBy('u.id') + ->limit(self::CHUNK_SIZE) + ->get(); + + if ($users->isEmpty()) { + return; + } + + $records = $users->map(fn ($user) => [ + 'permission_id' => $permissionId, + 'assignable_id' => $user->id, + 'assignable_type' => User::class, + ])->all(); + + DB::table('assignables')->insert($records); + $lastUserId = $users->last()->id; + } while ($users->count() === self::CHUNK_SIZE); + } +}; diff --git a/resources/jscomposition/cases/casesDetail/components/CaseDetail.vue b/resources/jscomposition/cases/casesDetail/components/CaseDetail.vue index b034ffa07f..8898eecc5e 100644 --- a/resources/jscomposition/cases/casesDetail/components/CaseDetail.vue +++ b/resources/jscomposition/cases/casesDetail/components/CaseDetail.vue @@ -34,6 +34,19 @@ const translate = ProcessMaker.i18n; const { Router } = window.ProcessMaker; const path = window.location.pathname; +const props = defineProps({ + permissions: { + type: Object, + default: () => ({ + overviewTabTask: true, + summaryTabTask: true, + completedTabTask: true, + formTabTask: true, + filesTabTask: true, + }), + }, +}); + const urlTabs = [ "errors", "tasks", @@ -45,21 +58,6 @@ const urlTabs = [ "requests", ]; -const tabDefault = computed(() => { - if (urlTabs.includes(window.location.hash.substring(1))) { - return window.location.hash.substring(1); - } - // This section is for the package-files, the issue should be fixed in page with vue-router - const routeResolved = Router.resolve(path); - if (routeResolved.route?.name && routeResolved.route?.meta?.package === "package-files") { - return "file_manager"; - } - if (isErrors()) { - return "errors"; - } - return "tasks"; -}); - const componentToShow = computed(() => { if (isTceCustomization()) { return TabSummary; @@ -67,7 +65,7 @@ const componentToShow = computed(() => { return null; }); -const tabs = [ +const tabs = computed(() => [ { name: translate.t("Errors"), href: "#errors", @@ -86,28 +84,28 @@ const tabs = [ name: translate.t("Overview"), href: "#overview", current: "overview", - show: !isTceCustomization(), + show: props.permissions.overviewTabTask && !isTceCustomization(), content: Overview, }, { name: translate.t("Summary"), href: "#summary", current: "summary", - show: getRequestStatus() !== "ERROR" && !isTceCustomization(), + show: props.permissions.summaryTabTask && getRequestStatus() !== "ERROR" && !isTceCustomization(), content: TabSummary, }, { name: translate.t("Completed & Form"), href: "#completed_form", current: "completed_form", - show: true, + show: props.permissions.completedTabTask || props.permissions.formTabTask, content: CompletedForms, }, { name: translate.t("File Manager"), href: "#file_manager", current: "file_manager", - show: true, + show: props.permissions.filesTabTask, content: TabFiles, }, { @@ -124,5 +122,30 @@ const tabs = [ show: getRequestCount() !== 1 && !isTceCustomization(), content: RequestTable, }, -]; +]); + +const tabDefault = computed(() => { + const requestedTab = window.location.hash.substring(1); + const visibleTab = (current) => tabs.value.find((tab) => tab.current === current && tab.show); + + if (urlTabs.includes(requestedTab) && visibleTab(requestedTab)) { + return requestedTab; + } + + // This section is for the package-files, the issue should be fixed in page with vue-router + const routeResolved = Router.resolve(path); + if ( + routeResolved.route?.name + && routeResolved.route?.meta?.package === "package-files" + && visibleTab("file_manager") + ) { + return "file_manager"; + } + + if (visibleTab("errors")) { + return "errors"; + } + + return tabs.value.find((tab) => tab.show)?.current || "tasks"; +}); diff --git a/resources/views/cases/edit.blade.php b/resources/views/cases/edit.blade.php index 767a6cddc5..d340a35dd8 100644 --- a/resources/views/cases/edit.blade.php +++ b/resources/views/cases/edit.blade.php @@ -19,14 +19,26 @@ @endsection +@php + $permissions = [ + 'overviewTabTask' => Auth::user()->can('overview-tab-task'), + 'summaryTabTask' => Auth::user()->can('summary-tab-task'), + 'completedTabTask' => Auth::user()->can('completed-tab-task'), + 'formTabTask' => Auth::user()->can('form-tab-task'), + 'filesTabTask' => Auth::user()->can('files-tab-task'), + ]; +@endphp + @section('content')
- + {{ __('Tasks') }} + @can('overview-tab-task') + @endcan + @can('summary-tab-task') + @endcan @if ($request->status === 'COMPLETED' && !$request->errors) @can('editData', $request) @endcan @endif + @can('completed-tab-task') + @endcan @if (count($files) > 0 && !hasPackage('package-files')) + @endcan @isset($addons) @foreach ($addons as $addon) @if (!empty($addon['title']))