@@ -40,6 +47,7 @@ import { useTimeAgo } from "../../../../composables/time.js";
import ProjectService from "../../../../services/ProjectService.js";
import ActivityItem from "./activity-item/ActivityItem.vue";
+import ActivityFilters from "./activity-filters/ActivityFilters.vue";
export default {
props: {
@@ -47,6 +55,7 @@ export default {
},
components: {
ActivityItem,
+ ActivityFilters,
},
emits: ["go-folder"],
@@ -119,24 +128,58 @@ export default {
const displayedGroupedLogs = computed(() => {
const search = searchText.value.trim().toLowerCase();
+ const f = filters.value;
return sortedLogs.value
- .filter((log) => !search || log._search.includes(search))
+ .filter((log) => {
+ if (search && !log._search.includes(search)) return false;
+
+ // Types
+ if (f.types.length && !f.types.includes(log.action)) return false;
+
+ // Users
+ if (f.users.length && !f.users.includes(log.user_email)) return false;
+
+ // Date
+ if (f.dateFrom && log.dateObj < f.dateFrom) return false;
+ if (f.dateTo) {
+ const endOfDay = new Date(f.dateTo);
+ endOfDay.setHours(23, 59, 59, 999);
+ if (log.dateObj > endOfDay) return false;
+ }
+
+ return true;
+ })
.reduce((groups, log) => {
const day = formatDay(log.dateObj);
-
groups[day] ??= [];
groups[day].push(log);
-
return groups;
}, {});
});
+
const hasDisplayedLogs = computed(() => Object.keys(displayedGroupedLogs.value).length > 0);
+ const filters = ref({
+ types: [],
+ users: [],
+ dateFrom: null,
+ dateTo: null,
+ });
+
+ const availableUsers = computed(() => [
+ ...new Set(logs.value.map((l) => l.user_email).filter(Boolean)),
+ ]);
+
+ const availableActions = computed(() => new Set(logs.value.map((l) => l.action)));
+
return {
displayedGroupedLogs,
hasDisplayedLogs,
searchText,
+ filters,
+ availableUsers,
+ availableActions,
formatTimeAgo,
};
},
diff --git a/src/components/specific/projects/project-history-activity/activity-filters/ActivityFilters.css b/src/components/specific/projects/project-history-activity/activity-filters/ActivityFilters.css
new file mode 100644
index 00000000..f5c2470a
--- /dev/null
+++ b/src/components/specific/projects/project-history-activity/activity-filters/ActivityFilters.css
@@ -0,0 +1,87 @@
+.activity-filters {
+ position: relative;
+
+ /* Filters button */
+ .activity-filters__btn {
+ gap: 6px;
+ .activity-filters__btn--active {
+ border-color: var(--color-primary);
+ background-color: rgba(47, 55, 74, .05);
+ color: var(--color-primary);
+ }
+ .activity-filters__badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 18px;
+ height: 18px;
+ padding: 0 4px;
+ border-radius: 9px;
+ background: var(--color-primary);
+ color: white;
+ font-size: 10px;
+ font-weight: 600;
+ }
+ }
+
+ /* Panel */
+ .activity-filters__panel {
+ position: absolute;
+ top: calc(100% + 6px);
+ right: 3px;
+ z-index: 100;
+ width: 320px;
+ background: var(--color-white);
+ border-radius: 6px;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+ overflow: auto;
+ .activity-filters__panel-header {
+ padding: 12px 16px;
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--color-primary);
+ border-bottom: 1px solid var(--color-silver-light, #f0f0f0);
+ }
+
+ /* Sections */
+ .activity-filters__section {
+ padding: 12px;
+ .activity-filters__title {
+ font-size: 11px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ margin-bottom: 3px;
+ }
+ .activity-filters__row {
+ padding: 2px 0;
+ font-size: 12px;
+ cursor: pointer;
+ user-select: none;
+
+ &.is-disabled {
+ opacity: 0.4;
+ cursor: default;
+ }
+ }
+ }
+ .activity-filters__date-range {
+ :deep() .not-empty {
+ label {
+ display: none
+ }
+ }
+ }
+
+ /* Footer */
+ .activity-filters__footer {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ gap: var(--spacing-unit);
+ padding: 12px 16px;
+ border-top: 1px solid var(--color-silver-light, #f0f0f0);
+ background: var(--color-white);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/components/specific/projects/project-history-activity/activity-filters/ActivityFilters.vue b/src/components/specific/projects/project-history-activity/activity-filters/ActivityFilters.vue
new file mode 100644
index 00000000..19f5f7cd
--- /dev/null
+++ b/src/components/specific/projects/project-history-activity/activity-filters/ActivityFilters.vue
@@ -0,0 +1,232 @@
+
+
+
+
+ {{ $t("t.filters") }}
+
+ {{ activeFilterCount }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t("ProjectOverview.activity.filters.types") }}
+
+
+
+
+
+
+
+
+
+ {{ $t("ProjectOverview.activity.filters.users") }}
+
+
+
+
+
+
+
+
+
+ {{ $t("ProjectOverview.activity.filters.period") }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.css b/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.css
index 86b8c403..df63f171 100644
--- a/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.css
+++ b/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.css
@@ -131,7 +131,7 @@
}
.red {
background: rgba(188, 0, 10, 0.1);
- color: var(--color-danger);
+ color: rgba(188, 0, 10, 1);
}
.teal {
background: rgba(27, 155, 162, 0.1);
diff --git a/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.vue b/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.vue
index d213c603..5a062773 100644
--- a/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.vue
+++ b/src/components/specific/projects/project-history-activity/activity-item/ActivityItem.vue
@@ -74,6 +74,28 @@
{{ $t("ProjectOverview.activity.newNameTitle") }}
{{ log.activity.details.newName }}
+
+