Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5d5a4e3
add rule manager
Amoki Jun 26, 2026
b972a50
assing constraint to folders
Amoki Jun 29, 2026
8408cdc
improve UX
Amoki Jun 29, 2026
ce9bacd
improve rename modal
Amoki Jun 29, 2026
66e4242
update lib & add modal when editing rule
Amoki Jul 1, 2026
6841740
use css files instead of scss and separate style and template
LrxGaelle Jul 3, 2026
32bc37c
fix css import
LrxGaelle Jul 3, 2026
2c4cfc2
add some UI fix
LrxGaelle Jul 6, 2026
7ac9e81
add some fixs
LrxGaelle Jul 8, 2026
67ca3ef
fix delete actions menu
LrxGaelle Jul 9, 2026
c706dfa
fix delete constraint call
LrxGaelle Jul 9, 2026
8a7e7c6
refactor manager navigation with tabs
LrxGaelle Jul 9, 2026
06d4e5c
fixed footer action in constraint form
LrxGaelle Jul 9, 2026
faaea9b
fix empty templates list view
LrxGaelle Jul 9, 2026
e3fb34d
preserve rule state when creating naming templates
LrxGaelle Jul 9, 2026
590d489
validate required fields before saving a rule
LrxGaelle Jul 10, 2026
ebdb7d1
Refactor and reorganize the style
LrxGaelle Jul 10, 2026
cffcb6a
start fix naming conflict modal
LrxGaelle Jul 16, 2026
467f1d9
add modal for stric & non-stric rule & add folder info icon
LrxGaelle Jul 21, 2026
0261c6e
Add some styles for hamonize & refactor and replace duplicated previ…
LrxGaelle Jul 21, 2026
5eb28f6
fix restore correct navigation after constraint and template creation
LrxGaelle Jul 24, 2026
74e4b99
fix autofocus newly added template element
LrxGaelle Jul 27, 2026
13c4ff9
clean up template creation navigation state
LrxGaelle Jul 27, 2026
71b14f6
fix hasNamingConflict for folder
LrxGaelle Jul 27, 2026
77aea00
refresh GED after naming constraint updates
LrxGaelle Jul 27, 2026
8491633
add naming constraint editor for conflicting documents
LrxGaelle Jul 27, 2026
c71e070
delete dead code
LrxGaelle Jul 28, 2026
0eb89d2
fix modal components style
LrxGaelle Jul 28, 2026
ff2b08c
fix overflow
LrxGaelle Jul 28, 2026
d60ff57
fix acutal name in conflict modal
LrxGaelle Jul 28, 2026
ee93e40
add translations
LrxGaelle Jul 28, 2026
3544d9b
add safeZoneModal when cancel NamingConstraintsForm
LrxGaelle Jul 29, 2026
ef0250a
refactor and move effective folder rule cache into NamingConstraintSe…
LrxGaelle Jul 29, 2026
923f603
add bulk import for naming template elements & add translations
LrxGaelle Jul 29, 2026
1166b42
delete unused translation key & add documents count on rename modal
LrxGaelle Jul 30, 2026
b05fa6b
add v-show on openNamingConstraintsManager to display only, on folder…
LrxGaelle Jul 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@
"vite": "^8.1.5",
"vite-plugin-environment": "^1.1.3"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
@download="$emit('download', file)"
@file-clicked="$emit('file-clicked', file)"
@manage-access="$emit('manage-access', file)"
@manage-naming-rule="$emit('manage-naming-rule', file)"
@open-tag-manager="$emit('open-tag-manager', file)"
@open-versioning-manager="$emit('open-versioning-manager', file)"
@open-visa-manager="$emit('open-visa-manager', file)"
Expand Down Expand Up @@ -288,6 +289,7 @@ export default {
"file-clicked",
"go-folders-view",
"manage-access",
"manage-naming-rule",
"open-tag-manager",
"open-versioning-manager",
"open-visa-manager",
Expand Down
116 changes: 111 additions & 5 deletions src/components/specific/files/files-manager/FilesManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
:initialSearchText="searchText"
@update:searchText="searchText = $event"
@upload-files="uploadFiles"
@manage-naming-conflicts="openNamingConflictsModal"
/>
<div class="files-manager__content">
<transition name="slide-fade-left">
Expand Down Expand Up @@ -76,6 +77,7 @@
:filesToUpload="filesToUpload"
:folder="currentFolder"
:foldersToUpload="foldersToUpload"
:hasNamingConflict="hasNamingConflict"
@back-parent-folder="backToParent"
@create-model="createModelFromFile"
@create-photosphere="createModelFromFile($event, MODEL_TYPE.PHOTOSPHERE)"
Expand All @@ -88,6 +90,7 @@
@file-clicked="onFileSelected"
@file-uploaded="$emit('file-uploaded')"
@manage-access="openAccessManager"
@manage-naming-rule="openFolderNamingConstraintManager"
@open-tag-manager="openTagManager"
@open-versioning-manager="openVersioningManager"
@open-visa-manager="openVisaManager"
Expand All @@ -111,6 +114,7 @@
@file-clicked="onFileSelected"
@go-folders-view="goFoldersView"
@manage-access="openAccessManager"
@manage-naming-rule="openFolderNamingConstraintManager"
@open-tag-manager="openTagManager"
@open-versioning-manager="openVersioningManager"
@open-visa-manager="openVisaManager"
Expand Down Expand Up @@ -205,12 +209,14 @@ import FileService from "../../../../services/FileService.js";
import TagService from "../../../../services/TagService";
import { useFiles } from "../../../../state/files.js";
import { useModels } from "../../../../state/models.js";
import { useNamingConstraints } from "../../../../state/naming-constraints.js";
import { useProjects } from "../../../../state/projects.js";
import { useSpaces } from "../../../../state/spaces.js";
import { useVisa } from "../../../../state/visa.js";
import { collectDescendants } from "../../../../utils/file-tree.js";
import { isFolder } from "../../../../utils/file-structure.js";
import { getFilesFromEvent } from "../../../../utils/files.js";
import { matchName } from "../../../../utils/naming-constraint.js";
import { isFullTotal } from "../../../../utils/spaces.js";
import { fileUploadInput } from "../../../../utils/upload.js";

Expand All @@ -225,6 +231,8 @@ import FilesManagerOnboarding from "./files-manager-onboarding/FilesManagerOnboa
import FileTree from "../file-tree/FileTree.vue";
import FileTreePreviewModal from "../file-tree-preview-modal/FileTreePreviewModal.vue";
import FolderAccessManager from "../folder-access-manager/FolderAccessManager.vue";
import FolderNamingConstraintManager from "../naming-constraint/FolderNamingConstraintManager.vue";
import NamingConflictModal from "../naming-constraint/NamingConflictModal.vue";
import FoldersTable from "../folder-table/FoldersTable.vue";
import SubscriptionModal from "../../subscriptions/subscription-modal/SubscriptionModal.vue";
import TagsMain from "../../tags/tags-main/TagsMain.vue";
Expand Down Expand Up @@ -264,6 +272,10 @@ export default {
type: Object,
required: true,
},
refreshFiles: {
type: Function,
required: true,
},
},
emits: ["file-uploaded", "file-updated", "model-created"],
setup(props, { emit }) {
Expand All @@ -280,7 +292,7 @@ export default {
const { createModel, createPhotosphere, deleteModels } = useModels();

const { fetchToValidateVisas, fetchCreatedVisas } = useVisa();

const { getEffectiveFolderRule } = useNamingConstraints();
const currentFolder = ref(null);
const currentFiles = ref([]);
const toValidateVisas = ref([]);
Expand Down Expand Up @@ -337,20 +349,55 @@ export default {

const filesToUpload = ref([]);
const foldersToUpload = ref([]);
const uploadFiles = async (event, folder = currentFolder.value) => {
const { files, folders } = await getFilesFromEvent(event);
const proceedUpload = async ({ files, folders }, folder) => {
files.forEach((file) => (file.folder = folder));

filesToUpload.value = files;
foldersToUpload.value = await Promise.all(
folders.map((f) => FileService.createFolderStructure(props.project, folder, f)),
);

setTimeout(() => {
filesToUpload.value = [];
foldersToUpload.value = [];
}, 10);
};
let folders = [];
const uploadFiles = async (event, folder = currentFolder.value) => {
const { files, folders } = await getFilesFromEvent(event);

const rule = await getEffectiveFolderRule(props.project, folder);
const invalidFiles = rule?.rule
? files.filter((file) => !matchName(file.name, rule.rule))
: [];

if (invalidFiles.length > 0) {
openModal({
component: NamingConflictModal,
props: {
project: props.project,
documents: invalidFiles.map((file, i) => ({ id: `upload-${i}`, name: file.name })),
rule,
persistChanges: false,
onClose: closeModal,
onConfirm: ({ renamed, deleted }) => {
const deletedIds = new Set(deleted.map((d) => d.id));
const renamedById = new Map(renamed.map((r) => [r.id, r.name]));
const finalFiles = invalidFiles
.map((file, i) => ({ file, id: `upload-${i}` }))
.filter(({ id }) => !deletedIds.has(id))
.map(({ file, id }) => {
const name = renamedById.get(id);
return name ? new File([file], name, { type: file.type }) : file;
});
const validFiles = files.filter((file) => matchName(file.name, rule.rule));
proceedUpload({ files: [...validFiles, ...finalFiles], folders }, folder);
},
},
});
return;
}

proceedUpload({ files, folders }, folder);
};

const loadingFileIds = ref([]);
const isCreatingModels = ref(false);
Expand Down Expand Up @@ -544,6 +591,49 @@ export default {
}, 100);
};

const openFolderNamingConstraintManager = (folder) => {
openSidePanel("right", {
component: FolderNamingConstraintManager,
props: {
project: props.project,
folder,
refreshFiles: props.refreshFiles,
},
});
};

const openNamingConflictsModal = async () => {
const conflicting = allFiles.value.filter((file) => file.naming_constraint_conflict);
if (conflicting.length === 0) {
pushNotification({
type: "success",
title: t("NamingConstraint.noConflictsTitle"),
message: t("NamingConstraint.noConflictsMessage"),
});
return;
}
const documents = await Promise.all(
conflicting.map(async (file) => {
const folder = allFolders.value.find((f) => f.id === file.parent_id);
const effective = folder ? await getEffectiveFolderRule(props.project, folder) : null;
return { ...file, namingRule: effective?.rule ?? null };
}),
);
openModal({
component: NamingConflictModal,
props: {
project: props.project,
documents,
allFolders: allFolders.value,
rule: null,
onClose: closeModal,
onConfirm: async () => {
await props.refreshFiles();
},
},
});
};

const visasLoading = ref(false);
const openVisaManager = (file) => {
onTabChange(filesTabs[2]);
Expand Down Expand Up @@ -683,6 +773,19 @@ export default {
const allFiles = computed(() => getFilesInFolder(props.fileStructure));
const allFolders = computed(() => getFoldersInFolder(props.fileStructure));

const hasNamingConflict = (folder) => {
if (!folder?.children?.length) {
return false;
}

return folder.children.some((child) => {
if (isFolder(child)) {
return hasNamingConflict(child);
}
return child.naming_constraint_conflict;
});
};

const filesTabs = [
{
id: "folders",
Expand Down Expand Up @@ -829,10 +932,13 @@ export default {
fileUploadInput,
goFoldersView,
goVisasView,
hasNamingConflict,
isFullTotal,
moveFiles,
onFileSelected,
openAccessManager,
openFolderNamingConstraintManager,
openNamingConflictsModal,
openFileDeleteModal,
openVisaDeleteModal,
openSidePanel,
Expand Down
Loading