+
diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBItem.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBItem.vue
new file mode 100644
index 0000000000..60d913cb39
--- /dev/null
+++ b/apps/web/src/common/modules/navigations/new-lsb/LSBItem.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterButton.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBRouterButton.vue
deleted file mode 100644
index 66e1926335..0000000000
--- a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterButton.vue
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- {{ props.label }}
-
-
-
-
-
-
-
-
-
diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterItem.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBRouterItem.vue
deleted file mode 100644
index d0c0e8f5c8..0000000000
--- a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterItem.vue
+++ /dev/null
@@ -1,152 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- {{ props.label }}
-
-
{{ props.label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBStarredTree.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBStarredTree.vue
new file mode 100644
index 0000000000..b0a061fe9f
--- /dev/null
+++ b/apps/web/src/common/modules/navigations/new-lsb/LSBStarredTree.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+ {{ $t('COMMON.STARRED') }}
+
+
+
+
+
+ {{ $t('COMMON.STARRED_NO_DATA') }}
+
+
+
+
diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBTitle.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBTitle.vue
new file mode 100644
index 0000000000..11e7a51d50
--- /dev/null
+++ b/apps/web/src/common/modules/navigations/new-lsb/LSBTitle.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+ {{ props.name }}
+
+
+
+
+
diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBTopTitle.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBTopTitle.vue
deleted file mode 100644
index 4fcc1fc8c0..0000000000
--- a/apps/web/src/common/modules/navigations/new-lsb/LSBTopTitle.vue
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
- {{ props.label }}
- {{ props.subText }}
-
-
-
-
-
-
-
diff --git a/apps/web/src/common/modules/navigations/new-lsb/composables/use-lsb-router-item-state.ts b/apps/web/src/common/modules/navigations/new-lsb/composables/use-lsb-router-item-state.ts
deleted file mode 100644
index 53bd568175..0000000000
--- a/apps/web/src/common/modules/navigations/new-lsb/composables/use-lsb-router-item-state.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import type { UnwrapRef, Ref } from 'vue';
-import { computed } from 'vue';
-import type { Location } from 'vue-router';
-import { useRoute, useRouter } from 'vue-router/composables';
-
-import { assetUrlConverter } from '@/lib/helper/asset-helper';
-
-import type { LSBIcon, LSBRouterPredicate } from '@/common/modules/navigations/new-lsb/type';
-
-interface UseLsbRouterItemProps {
- to?: Ref
>;
- icon?: Ref>;
- imgIcon?: Ref>;
- predicate?: LSBRouterPredicate;
-}
-export const useLsbRouterItemState = (props: UnwrapRef) => {
- const router = useRouter();
- const route = useRoute();
-
- const isSelected = computed(() => {
- if (!props.to) return false;
-
- if (props.predicate) {
- return props.predicate(props.to, route);
- }
-
- const resolved = router.resolve(props.to);
- if (!resolved) return false;
-
- let currentPath = route.fullPath;
- if (currentPath.indexOf('?') > 0) {
- currentPath = currentPath.slice(0, currentPath.indexOf('?'));
- }
- const resolvedHref = resolved.href;
- return currentPath === resolvedHref;
- });
- const iconName = computed(() => {
- if (!props.icon) return '';
- if (typeof props.icon === 'string') return props.icon;
- return props.icon.name;
- });
- const iconColor = computed(() => {
- if (!props.icon) return 'inherit';
- if (typeof props.icon === 'string') return 'inherit';
- return props.icon.color || 'inherit';
- });
- const imgIconUrl = computed(() => (props.imgIcon ? assetUrlConverter(props.imgIcon) : ''));
-
- return {
- isSelected,
- iconName,
- iconColor,
- imgIconUrl,
- };
-};
diff --git a/apps/web/src/common/modules/navigations/new-lsb/type.ts b/apps/web/src/common/modules/navigations/new-lsb/type.ts
index 39f4908eb1..e05ca944e4 100644
--- a/apps/web/src/common/modules/navigations/new-lsb/type.ts
+++ b/apps/web/src/common/modules/navigations/new-lsb/type.ts
@@ -1,6 +1,21 @@
+import type { TranslateResult } from 'vue-i18n';
import type { Location, Route } from 'vue-router';
+import type { TreeNodeDisplayType, TreeNodeIcon, TreeNodeLink } from '@cloudforet/mirinae/types/data-display/tree/new-tree/type';
+
+import type { FavoriteOptions } from '@/common/modules/favorites/favorite-button/type';
-export type LSBIcon = string | { name: string; color?: string; };
export type HighlightTagType = 'new' | 'beta' | 'update';
export type LSBRouterPredicate = (to: Location, currentRoute: Route) => boolean;
+export type LSBItemFavoriteVisibility = 'always' | 'active-only' | 'hovered-only' | 'none';
+
+export interface LSBItemProps {
+ id: string;
+ name: TranslateResult;
+ icon?: TreeNodeIcon;
+ link: TreeNodeLink;
+ displayType?: TreeNodeDisplayType;
+ highlightTag?: HighlightTagType;
+ favoriteOptions?: FavoriteOptions;
+ favoriteVisibility?: LSBItemFavoriteVisibility;
+}
diff --git a/apps/web/src/common/modules/page-layouts/type.ts b/apps/web/src/common/modules/page-layouts/type.ts
index 4343f25bac..9d3acd34e0 100644
--- a/apps/web/src/common/modules/page-layouts/type.ts
+++ b/apps/web/src/common/modules/page-layouts/type.ts
@@ -1,7 +1,7 @@
import type { TranslateResult } from 'vue-i18n';
import type { Location } from 'vue-router';
-import type { ProjectGroupTreeNodeData } from '@/services/project/v-shared/types/project-tree-type';
+import type { ProjectGroupTreeNodeData } from '@/common/modules/project/project-tree-type';
export interface Breadcrumb {
name: TranslateResult|string;
diff --git a/apps/web/src/common/modules/project/ProjectSelectDropdown.vue b/apps/web/src/common/modules/project/ProjectSelectDropdown.vue
index 85eb705042..f0d5e3d4d8 100644
--- a/apps/web/src/common/modules/project/ProjectSelectDropdown.vue
+++ b/apps/web/src/common/modules/project/ProjectSelectDropdown.vue
@@ -17,15 +17,16 @@ import type { ReferenceMap } from '@/store/reference/type';
import getRandomId from '@/lib/random-id-generator';
import ErrorHandler from '@/common/composables/error/errorHandler';
-
-import { indigo, peacock } from '@/styles/colors';
-
-import type { ProjectTreeOptions } from '@/services/project/v-shared/composables/use-project-tree';
-import { useProjectTree } from '@/services/project/v-shared/composables/use-project-tree';
import type {
ProjectTreeItem, ProjectTreeNodeData, ProjectTreeRoot, ProjectTreeItemType,
ProjectTreeNode,
-} from '@/services/project/v-shared/types/project-tree-type';
+} from '@/common/modules/project/project-tree-type';
+import type { ProjectTreeOptions } from '@/common/modules/project/use-project-tree';
+import { useProjectTree } from '@/common/modules/project/use-project-tree';
+
+import { indigo, peacock } from '@/styles/colors';
+
+
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
interface ProjectGroupSelectOptions {
diff --git a/apps/web/src/services/project/v-shared/types/project-tree-type.ts b/apps/web/src/common/modules/project/project-tree-type.ts
similarity index 100%
rename from apps/web/src/services/project/v-shared/types/project-tree-type.ts
rename to apps/web/src/common/modules/project/project-tree-type.ts
diff --git a/apps/web/src/services/project/v-shared/composables/use-project-tree.ts b/apps/web/src/common/modules/project/use-project-tree.ts
similarity index 99%
rename from apps/web/src/services/project/v-shared/composables/use-project-tree.ts
rename to apps/web/src/common/modules/project/use-project-tree.ts
index 00b833a92b..5c7867039c 100644
--- a/apps/web/src/services/project/v-shared/composables/use-project-tree.ts
+++ b/apps/web/src/common/modules/project/use-project-tree.ts
@@ -11,7 +11,7 @@ import type { ProjectGroupModel } from '@/api-clients/identity/project-group/sch
import type { ProjectListParameters } from '@/api-clients/identity/project/schema/api-verbs/list';
import type { ProjectModel } from '@/api-clients/identity/project/schema/model';
-import type { ProjectTreeItemType, ProjectTreeNodeData } from '@/services/project/v-shared/types/project-tree-type';
+import type { ProjectTreeItemType, ProjectTreeNodeData } from '@/common/modules/project/project-tree-type';
type ProjectGroupListResponse = ListResponse;
diff --git a/apps/web/src/lib/config/global-config/feature-schema.ts b/apps/web/src/lib/config/global-config/feature-schema.ts
index 2ddd0251b7..15999061e8 100644
--- a/apps/web/src/lib/config/global-config/feature-schema.ts
+++ b/apps/web/src/lib/config/global-config/feature-schema.ts
@@ -17,6 +17,9 @@ export const initialFeatureSchema: FeatureSchemaType = {
visibleAlertTabAtDetail: true,
},
},
+ V2: {
+ menu: { [MENU_ID.PROJECT]: true },
+ },
},
[FEATURES.SERVICE_ACCOUNT]: {
currentVersion: 'V1',
diff --git a/apps/web/src/services/alert-manager/v1/components/AlertMainAlertCreateModal.vue b/apps/web/src/services/alert-manager/v1/components/AlertMainAlertCreateModal.vue
index 2c55b7b58b..2038e5a3ed 100644
--- a/apps/web/src/services/alert-manager/v1/components/AlertMainAlertCreateModal.vue
+++ b/apps/web/src/services/alert-manager/v1/components/AlertMainAlertCreateModal.vue
@@ -21,9 +21,9 @@ import { showSuccessMessage } from '@/lib/helper/notice-alert-helper';
import ErrorHandler from '@/common/composables/error/errorHandler';
import { useProxyValue } from '@/common/composables/proxy-state';
+import type { ProjectTreeNodeData } from '@/common/modules/project/project-tree-type';
import ProjectSelectDropdown from '@/common/modules/project/ProjectSelectDropdown.vue';
-import type { ProjectTreeNodeData } from '@/services/project/v-shared/types/project-tree-type';
const props = defineProps<{
visible: boolean;
diff --git a/apps/web/src/services/alert-manager/v1/components/EscalationPolicyForm.vue b/apps/web/src/services/alert-manager/v1/components/EscalationPolicyForm.vue
index 550a34591b..4595574386 100644
--- a/apps/web/src/services/alert-manager/v1/components/EscalationPolicyForm.vue
+++ b/apps/web/src/services/alert-manager/v1/components/EscalationPolicyForm.vue
@@ -22,13 +22,13 @@ import { useUserStore } from '@/store/user/user-store';
import { referenceRouter } from '@/lib/reference/referenceRouter';
import { useFormValidator } from '@/common/composables/form-validator';
+import type { ProjectTreeNodeData } from '@/common/modules/project/project-tree-type';
import ProjectSelectDropdown from '@/common/modules/project/ProjectSelectDropdown.vue';
import EscalationPolicyFormRulesInput from '@/services/alert-manager/v1/components/EscalationPolicyFormRulesInput.vue';
import { ACTION } from '@/services/alert-manager/v1/constants/alert-constant';
import { useEscalationPolicyFormStore } from '@/services/alert-manager/v1/stores/escalation-policy-form-store';
import type { ActionMode } from '@/services/alert-manager/v1/types/alert-type';
-import type { ProjectTreeNodeData } from '@/services/project/v-shared/types/project-tree-type';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
const props = withDefaults(defineProps<{
diff --git a/apps/web/src/services/iam/components/AppManagementFormModal.vue b/apps/web/src/services/iam/components/AppManagementFormModal.vue
index 4d9017db5d..a44e91cdbc 100644
--- a/apps/web/src/services/iam/components/AppManagementFormModal.vue
+++ b/apps/web/src/services/iam/components/AppManagementFormModal.vue
@@ -26,13 +26,13 @@ import { i18n } from '@/translations';
import { useAppContextStore } from '@/store/app-context/app-context-store';
import ErrorHandler from '@/common/composables/error/errorHandler';
+import type { ProjectTreeNodeData } from '@/common/modules/project/project-tree-type';
import ProjectSelectDropdown from '@/common/modules/project/ProjectSelectDropdown.vue';
import { useRoleFormatter } from '@/services/iam/composables/refined-table-data';
import { getInputItemsFromTagKeys } from '@/services/iam/composables/tag-data';
import { APP_DROPDOWN_MODAL_TYPE } from '@/services/iam/constants/app-constant';
import { useAppPageStore } from '@/services/iam/store/app-page-store';
-import type { ProjectTreeNodeData } from '@/services/project/v-shared/types/project-tree-type';
interface AppDropdownMenuItem extends SelectDropdownMenuItem {
diff --git a/apps/web/src/services/ops-flow/components/BoardLSB.vue b/apps/web/src/services/ops-flow/components/BoardLSB.vue
index 98bb8d98c5..a55962ba56 100644
--- a/apps/web/src/services/ops-flow/components/BoardLSB.vue
+++ b/apps/web/src/services/ops-flow/components/BoardLSB.vue
@@ -3,10 +3,9 @@ import { PIconButton } from '@cloudforet/mirinae';
import LSBContainer from '@/common/modules/navigations/new-lsb/LSBContainer.vue';
import LSBDivider from '@/common/modules/navigations/new-lsb/LSBDivider.vue';
+import LSBItem from '@/common/modules/navigations/new-lsb/LSBItem.vue';
import LSBLoadingSpinner from '@/common/modules/navigations/new-lsb/LSBLoadingSpinner.vue';
-import LSBRouterButton from '@/common/modules/navigations/new-lsb/LSBRouterButton.vue';
-import LSBRouterItem from '@/common/modules/navigations/new-lsb/LSBRouterItem.vue';
-import LSBTopTitle from '@/common/modules/navigations/new-lsb/LSBTopTitle.vue';
+import LSBTitle from '@/common/modules/navigations/new-lsb/LSBTitle.vue';
import type { LSBRouterPredicate } from '@/common/modules/navigations/new-lsb/type';
import { useAvailableCategories } from '@/services/ops-flow/composables/use-available-categories';
@@ -24,40 +23,43 @@ const { availableCategories, isLoading, refetch } = useAvailableCategories();
-
- {{ $t('OPSFLOW.ALL_TASKS', {
+ {{ $t('OPSFLOW.ALL_TASKS', {
tasks: taskManagementTemplateStore.templates.tasks
}) }}
-
+
-
- {{ taskManagementTemplateStore.templates.TaskCategory }}
-
+
+ {{ taskManagementTemplateStore.templates.TaskCategory }}
+
-
+
-
- {{ category.name }}
-
+
diff --git a/apps/web/src/services/project/v-shared/composables/queries/use-project-group-query.ts b/apps/web/src/services/project/v-shared/composables/queries/use-project-group-query.ts
new file mode 100644
index 0000000000..ace2516c32
--- /dev/null
+++ b/apps/web/src/services/project/v-shared/composables/queries/use-project-group-query.ts
@@ -0,0 +1,45 @@
+import { computed, type Ref } from 'vue';
+
+import { useQuery, useQueryClient } from '@tanstack/vue-query';
+
+import { useProjectGroupApi } from '@/api-clients/identity/project-group/composables/use-project-group-api';
+import type { ProjectGroupModel } from '@/api-clients/identity/project-group/schema/model';
+
+export const useProjectGroupQuery = ({
+ projectGroupId,
+ enabled,
+}: {
+ projectGroupId: Ref;
+ enabled?: Ref;
+}) => {
+ const { projectGroupAPI, projectGroupListQueryKey, projectGroupQueryKey } = useProjectGroupApi();
+ const queryKey = computed(() => [...projectGroupQueryKey.value, projectGroupId.value]);
+ const projectGroupQuery = useQuery({
+ queryKey,
+ queryFn: () => projectGroupAPI.get({ project_group_id: projectGroupId.value as string }),
+ enabled: computed(() => {
+ if (!projectGroupId.value) return false;
+ return enabled ? enabled.value : true;
+ }),
+ staleTime: 1000 * 60 * 5, // 5 minutes
+ gcTime: 1000 * 60 * 1, // 1 minutes
+ });
+
+ const queryClient = useQueryClient();
+ const setQueryData = (newData: ProjectGroupModel) => {
+ queryClient.setQueryData(queryKey.value, newData);
+ };
+ const invalidateQuery = () => {
+ queryClient.invalidateQueries({ queryKey: queryKey.value });
+ };
+ const invalidateAllQueries = () => {
+ queryClient.invalidateQueries({ queryKey: projectGroupListQueryKey.value });
+ };
+
+ return {
+ ...projectGroupQuery,
+ setQueryData,
+ invalidateQuery,
+ invalidateAllQueries,
+ };
+};
diff --git a/apps/web/src/services/project/v-shared/composables/queries/use-project-groups-query.ts b/apps/web/src/services/project/v-shared/composables/queries/use-project-groups-query.ts
new file mode 100644
index 0000000000..bc601faf77
--- /dev/null
+++ b/apps/web/src/services/project/v-shared/composables/queries/use-project-groups-query.ts
@@ -0,0 +1,28 @@
+import type { Ref } from 'vue';
+
+import { useQuery } from '@tanstack/vue-query';
+
+import { ApiQueryHelper } from '@cloudforet/core-lib/space-connector/helper';
+
+import { useProjectGroupApi } from '@/api-clients/identity/project-group/composables/use-project-group-api';
+
+export const useProjectGroupsQuery = (ops?: { enabled: Ref }) => {
+ const { projectGroupAPI, projectGroupListQueryKey } = useProjectGroupApi();
+ const projectGroupsApiQuery = new ApiQueryHelper().setOnly('name', 'project_group_id');
+ const { data, isLoading, error } = useQuery({
+ queryKey: projectGroupListQueryKey,
+ queryFn: async () => {
+ const res = await projectGroupAPI.list({
+ query: projectGroupsApiQuery.data,
+ });
+ return res.results ?? [];
+ },
+ enabled: ops?.enabled,
+ staleTime: 1000 * 60 * 5, // 5 minutes
+ gcTime: 1000 * 60 * 1, // 1 minutes
+ });
+
+ return {
+ data, isLoading, error,
+ };
+};
diff --git a/apps/web/src/services/project/v-shared/composables/use-project-group-names.ts b/apps/web/src/services/project/v-shared/composables/use-project-group-names.ts
new file mode 100644
index 0000000000..ee09904c12
--- /dev/null
+++ b/apps/web/src/services/project/v-shared/composables/use-project-group-names.ts
@@ -0,0 +1,23 @@
+import type { Ref } from 'vue';
+import { computed } from 'vue';
+
+import { useProjectGroupsQuery } from '@/services/project/v-shared/composables/queries/use-project-groups-query';
+
+export const useProjectGroupNames = ({
+ projectGroupId, enabled,
+}: {
+ projectGroupId: Ref;
+ enabled: Ref;
+}) => {
+ const { data } = useProjectGroupsQuery({ enabled });
+
+ const projectGroupNames = computed(() => {
+ if (!data.value) return [];
+ if (projectGroupId.value) {
+ return data.value.filter((pg) => pg.project_group_id !== projectGroupId.value).map((item) => item.name);
+ }
+ return data.value.map((item) => item.name);
+ });
+
+ return projectGroupNames;
+};
diff --git a/apps/web/src/services/project/v-shared/tree/TreeItem.vue b/apps/web/src/services/project/v-shared/tree/TreeItem.vue
deleted file mode 100644
index e0eb6175f3..0000000000
--- a/apps/web/src/services/project/v-shared/tree/TreeItem.vue
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
-
-
-
-
diff --git a/apps/web/src/services/project/v-shared/tree/TreeView.vue b/apps/web/src/services/project/v-shared/tree/TreeView.vue
deleted file mode 100644
index d4df77e367..0000000000
--- a/apps/web/src/services/project/v-shared/tree/TreeView.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/web/src/services/project/v-shared/tree/type.ts b/apps/web/src/services/project/v-shared/tree/type.ts
deleted file mode 100644
index ebfccbb339..0000000000
--- a/apps/web/src/services/project/v-shared/tree/type.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { Location } from 'vue-router/types/router';
-
-export interface TreeNode {
- id: string;
- depth: number;
- isOpen?: boolean;
- data: T;
- loading?: boolean;
- children?: TreeNode[];
-}
-
-export interface TreeData {
- to?: Location;
-}
-export interface TreeDisplayMap {
- [id: string]: {
- isOpen: boolean;
- }
-}
diff --git a/apps/web/src/services/project/v1/ProjectContainer.vue b/apps/web/src/services/project/v1/ProjectContainer.vue
index 8470bdb3c8..0f588e5560 100644
--- a/apps/web/src/services/project/v1/ProjectContainer.vue
+++ b/apps/web/src/services/project/v1/ProjectContainer.vue
@@ -10,12 +10,12 @@ import CenteredPageLayout from '@/common/modules/page-layouts/CenteredPageLayout
import GeneralPageLayout from '@/common/modules/page-layouts/GeneralPageLayout.vue';
import VerticalPageLayout from '@/common/modules/page-layouts/VerticalPageLayout.vue';
-import ProjectFormModal from '@/services/project/v-shared/components/ProjectFormModal.vue';
-import ProjectMainProjectGroupFormModal from '@/services/project/v-shared/components/ProjectMainProjectGroupFormModal.vue';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
-import { useProjectTreeStore } from '@/services/project/v-shared/stores/project-tree-store';
+import ProjectFormModal from '@/services/project/v1/components/ProjectFormModal.vue';
+import ProjectMainProjectGroupFormModal from '@/services/project/v1/components/ProjectMainProjectGroupFormModal.vue';
import ProjectLSB from '@/services/project/v1/ProjectLSB.vue';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
+import { useProjectTreeStore } from '@/services/project/v1/stores/project-tree-store';
diff --git a/apps/web/src/services/project/v1/ProjectLSB.vue b/apps/web/src/services/project/v1/ProjectLSB.vue
index cca43a4483..37963f1d2a 100644
--- a/apps/web/src/services/project/v1/ProjectLSB.vue
+++ b/apps/web/src/services/project/v1/ProjectLSB.vue
@@ -29,10 +29,10 @@ import { MENU_ITEM_TYPE } from '@/common/modules/navigations/lsb/type';
import { indigo, peacock } from '@/styles/colors';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
import ProjectMainTree from '@/services/project/v1/components/ProjectMainTree.vue';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
import { useProjectDetailPageStore } from '@/services/project/v1/stores/project-detail-page-store';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
const route = useRoute();
const allReferenceStore = useAllReferenceStore();
diff --git a/apps/web/src/services/project/v1/components/ProjectDetailTabHeader.vue b/apps/web/src/services/project/v1/components/ProjectDetailTabHeader.vue
index a0e5257b0a..a2537ee869 100644
--- a/apps/web/src/services/project/v1/components/ProjectDetailTabHeader.vue
+++ b/apps/web/src/services/project/v1/components/ProjectDetailTabHeader.vue
@@ -51,14 +51,14 @@ import { gray, peacock } from '@/styles/colors';
import { ASSET_INVENTORY_ROUTE } from '@/services/asset-inventory/routes/route-constant';
import { DYNAMIC_COST_QUERY_SET_PARAMS } from '@/services/cost-explorer/constants/managed-cost-analysis-query-sets';
import { COST_EXPLORER_ROUTE } from '@/services/cost-explorer/routes/route-constant';
-import ProjectFormModal from '@/services/project/v-shared/components/ProjectFormModal.vue';
-import ProjectMainProjectGroupMoveModal from '@/services/project/v-shared/components/ProjectMainProjectGroupMoveModal.vue';
-import ProjectMemberInviteModal from '@/services/project/v-shared/components/ProjectMemberInviteModal.vue';
-import ProjectTagsModal from '@/services/project/v-shared/components/ProjectTagsModal.vue';
-import { useProjectTreeStore } from '@/services/project/v-shared/stores/project-tree-store';
+import ProjectFormModal from '@/services/project/v1/components/ProjectFormModal.vue';
import ProjectMainDeleteModal from '@/services/project/v1/components/ProjectMainDeleteModal.vue';
+import ProjectMainProjectGroupMoveModal from '@/services/project/v1/components/ProjectMainProjectGroupMoveModal.vue';
+import ProjectMemberInviteModal from '@/services/project/v1/components/ProjectMemberInviteModal.vue';
+import ProjectTagsModal from '@/services/project/v1/components/ProjectTagsModal.vue';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
import { useProjectDetailPageStore } from '@/services/project/v1/stores/project-detail-page-store';
+import { useProjectTreeStore } from '@/services/project/v1/stores/project-tree-store';
import { SERVICE_ACCOUNT_ROUTE } from '@/services/service-account/routes/route-constant';
diff --git a/apps/web/src/services/project/v-shared/components/ProjectFormModal.vue b/apps/web/src/services/project/v1/components/ProjectFormModal.vue
similarity index 100%
rename from apps/web/src/services/project/v-shared/components/ProjectFormModal.vue
rename to apps/web/src/services/project/v1/components/ProjectFormModal.vue
diff --git a/apps/web/src/services/project/v-shared/components/ProjectGroupMemberManagementModal.vue b/apps/web/src/services/project/v1/components/ProjectGroupMemberManagementModal.vue
similarity index 99%
rename from apps/web/src/services/project/v-shared/components/ProjectGroupMemberManagementModal.vue
rename to apps/web/src/services/project/v1/components/ProjectGroupMemberManagementModal.vue
index a460bafd7c..da282e066b 100644
--- a/apps/web/src/services/project/v-shared/components/ProjectGroupMemberManagementModal.vue
+++ b/apps/web/src/services/project/v1/components/ProjectGroupMemberManagementModal.vue
@@ -28,7 +28,7 @@ import ErrorHandler from '@/common/composables/error/errorHandler';
import { useProxyValue } from '@/common/composables/proxy-state';
import { useRoleFormatter } from '@/services/iam/composables/refined-table-data';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
interface Props {
diff --git a/apps/web/src/services/project/v1/components/ProjectMainProjectCard.vue b/apps/web/src/services/project/v1/components/ProjectMainProjectCard.vue
index a4aebb2bd5..cf3261b267 100644
--- a/apps/web/src/services/project/v1/components/ProjectMainProjectCard.vue
+++ b/apps/web/src/services/project/v1/components/ProjectMainProjectCard.vue
@@ -19,9 +19,9 @@ import { FAVORITE_TYPE } from '@/common/modules/favorites/favorite-button/type';
import { peacock } from '@/styles/colors';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
import type { ProjectCardItemType } from '@/services/project/v-shared/types/project-type';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
import { SERVICE_ACCOUNT_ROUTE } from '@/services/service-account/routes/route-constant';
interface Props {
diff --git a/apps/web/src/services/project/v1/components/ProjectMainProjectGroupCard.vue b/apps/web/src/services/project/v1/components/ProjectMainProjectGroupCard.vue
index 1411badfd1..09e45126a9 100644
--- a/apps/web/src/services/project/v1/components/ProjectMainProjectGroupCard.vue
+++ b/apps/web/src/services/project/v1/components/ProjectMainProjectGroupCard.vue
@@ -14,9 +14,9 @@ import { FAVORITE_TYPE } from '@/common/modules/favorites/favorite-button/type';
import { indigo } from '@/styles/colors';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
import type { ProjectCardItemType } from '@/services/project/v-shared/types/project-type';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
interface Props {
item: ProjectCardItemType;
diff --git a/apps/web/src/services/project/v-shared/components/ProjectMainProjectGroupFormModal.vue b/apps/web/src/services/project/v1/components/ProjectMainProjectGroupFormModal.vue
similarity index 54%
rename from apps/web/src/services/project/v-shared/components/ProjectMainProjectGroupFormModal.vue
rename to apps/web/src/services/project/v1/components/ProjectMainProjectGroupFormModal.vue
index 171a9e3cb1..62fd0f1b4f 100644
--- a/apps/web/src/services/project/v-shared/components/ProjectMainProjectGroupFormModal.vue
+++ b/apps/web/src/services/project/v1/components/ProjectMainProjectGroupFormModal.vue
@@ -1,51 +1,66 @@
@@ -146,7 +152,7 @@ watch(() => props.projectGroupId, async (after) => {
fade
backdrop
:visible.sync="state.proxyVisible"
- :disabled="state.loading || !isAllValid || storeState.projectGroups[props.projectGroupId]?.name === projectGroupName"
+ :disabled="isProcessing || !isAllValid || projectGroup?.name === projectGroupName"
@confirm="confirm"
>
diff --git a/apps/web/src/services/project/v-shared/components/ProjectMainProjectGroupMoveModal.vue b/apps/web/src/services/project/v1/components/ProjectMainProjectGroupMoveModal.vue
similarity index 98%
rename from apps/web/src/services/project/v-shared/components/ProjectMainProjectGroupMoveModal.vue
rename to apps/web/src/services/project/v1/components/ProjectMainProjectGroupMoveModal.vue
index 10e973fbe0..8f066fe304 100644
--- a/apps/web/src/services/project/v-shared/components/ProjectMainProjectGroupMoveModal.vue
+++ b/apps/web/src/services/project/v1/components/ProjectMainProjectGroupMoveModal.vue
@@ -17,9 +17,9 @@ import { showSuccessMessage } from '@/lib/helper/notice-alert-helper';
import ErrorHandler from '@/common/composables/error/errorHandler';
import { useProxyValue } from '@/common/composables/proxy-state';
+import type { ProjectTreeNodeData } from '@/common/modules/project/project-tree-type';
import ProjectSelectDropdown from '@/common/modules/project/ProjectSelectDropdown.vue';
-import type { ProjectTreeNodeData } from '@/services/project/v-shared/types/project-tree-type';
interface Props {
diff --git a/apps/web/src/services/project/v1/components/ProjectMainTree.vue b/apps/web/src/services/project/v1/components/ProjectMainTree.vue
index 084cd23dfb..c78b4b006a 100644
--- a/apps/web/src/services/project/v1/components/ProjectMainTree.vue
+++ b/apps/web/src/services/project/v1/components/ProjectMainTree.vue
@@ -8,6 +8,7 @@ import { useRoute } from 'vue-router/composables';
import { isEqual } from 'lodash';
import { PI, PTreeView } from '@cloudforet/mirinae';
+import type { TreeData, TreeDisplayMap, TreeNode } from '@cloudforet/mirinae/types/data-display/tree/tree-view/type';
import { i18n } from '@/translations';
@@ -22,9 +23,8 @@ import type { Breadcrumb } from '@/common/modules/page-layouts/type';
import { indigo, peacock } from '@/styles/colors';
-import { useProjectTreeStore } from '@/services/project/v-shared/stores/project-tree-store';
-import type { TreeNode, TreeDisplayMap, TreeData } from '@/services/project/v-shared/tree/type';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
+import { useProjectTreeStore } from '@/services/project/v1/stores/project-tree-store';
interface ProjectDataType extends TreeData {
name: string;
diff --git a/apps/web/src/services/project/v-shared/components/ProjectMemberInviteModal.vue b/apps/web/src/services/project/v1/components/ProjectMemberInviteModal.vue
similarity index 100%
rename from apps/web/src/services/project/v-shared/components/ProjectMemberInviteModal.vue
rename to apps/web/src/services/project/v1/components/ProjectMemberInviteModal.vue
diff --git a/apps/web/src/services/project/v-shared/components/ProjectTagsModal.vue b/apps/web/src/services/project/v1/components/ProjectTagsModal.vue
similarity index 100%
rename from apps/web/src/services/project/v-shared/components/ProjectTagsModal.vue
rename to apps/web/src/services/project/v1/components/ProjectTagsModal.vue
diff --git a/apps/web/src/services/project/v1/composables/use-project-favorite.ts b/apps/web/src/services/project/v1/composables/use-project-favorite.ts
index a477bf6e94..e30a82cb6b 100644
--- a/apps/web/src/services/project/v1/composables/use-project-favorite.ts
+++ b/apps/web/src/services/project/v1/composables/use-project-favorite.ts
@@ -16,7 +16,7 @@ import { useFavoriteStore } from '@/common/modules/favorites/favorite-button/sto
import { FAVORITE_TYPE } from '@/common/modules/favorites/favorite-button/type';
import type { FavoriteItem } from '@/common/modules/favorites/favorite-button/type';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
export const useProjectFavorite = () => {
diff --git a/apps/web/src/services/project/v1/composables/use-project-tree-data.ts b/apps/web/src/services/project/v1/composables/use-project-tree-data.ts
index 7c3f982ed0..791dfb7699 100644
--- a/apps/web/src/services/project/v1/composables/use-project-tree-data.ts
+++ b/apps/web/src/services/project/v1/composables/use-project-tree-data.ts
@@ -7,13 +7,14 @@ import type { Location } from 'vue-router';
import { get } from 'lodash';
+import type { TreeDisplayMap, TreeNode } from '@cloudforet/mirinae/types/data-display/tree/tree-view/type';
+
import { useAllReferenceStore } from '@/store/reference/all-reference-store';
import type { ProjectGroupReferenceMap } from '@/store/reference/project-group-reference-store';
import type { ProjectReferenceMap } from '@/store/reference/project-reference-store';
-import { useProjectTreeStore } from '@/services/project/v-shared/stores/project-tree-store';
-import type { TreeNode, TreeDisplayMap } from '@/services/project/v-shared/tree/type';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
+import { useProjectTreeStore } from '@/services/project/v1/stores/project-tree-store';
interface ParentGroupItem {
name: string;
diff --git a/apps/web/src/services/project/v1/pages/ProjectDetailPageLegacy.vue b/apps/web/src/services/project/v1/pages/ProjectDetailPageLegacy.vue
index c74b484d78..8b6507a616 100644
--- a/apps/web/src/services/project/v1/pages/ProjectDetailPageLegacy.vue
+++ b/apps/web/src/services/project/v1/pages/ProjectDetailPageLegacy.vue
@@ -39,11 +39,11 @@ import { RECENT_TYPE } from '@/common/modules/navigations/type';
import { peacock } from '@/styles/colors';
-import ProjectFormModal from '@/services/project/v-shared/components/ProjectFormModal.vue';
-import ProjectMainProjectGroupMoveModal from '@/services/project/v-shared/components/ProjectMainProjectGroupMoveModal.vue';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
+import ProjectFormModal from '@/services/project/v1/components/ProjectFormModal.vue';
+import ProjectMainProjectGroupMoveModal from '@/services/project/v1/components/ProjectMainProjectGroupMoveModal.vue';
import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant';
import { useProjectDetailPageStore } from '@/services/project/v1/stores/project-detail-page-store';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
interface Props {
diff --git a/apps/web/src/services/project/v1/pages/ProjectMainPage.vue b/apps/web/src/services/project/v1/pages/ProjectMainPage.vue
index 9d1bd868a5..e5fd8050f1 100644
--- a/apps/web/src/services/project/v1/pages/ProjectMainPage.vue
+++ b/apps/web/src/services/project/v1/pages/ProjectMainPage.vue
@@ -25,12 +25,12 @@ import { useGnbStore } from '@/common/modules/navigations/stores/gnb-store';
import { indigo, peacock } from '@/styles/colors';
-import ProjectGroupMemberManagementModal from '@/services/project/v-shared/components/ProjectGroupMemberManagementModal.vue';
-import ProjectMainProjectGroupMoveModal from '@/services/project/v-shared/components/ProjectMainProjectGroupMoveModal.vue';
-import { useProjectPageStore } from '@/services/project/v-shared/stores/project-page-store';
-import { useProjectTreeStore } from '@/services/project/v-shared/stores/project-tree-store';
+import ProjectGroupMemberManagementModal from '@/services/project/v1/components/ProjectGroupMemberManagementModal.vue';
import ProjectMain from '@/services/project/v1/components/ProjectMain.vue';
import ProjectMainDeleteModal from '@/services/project/v1/components/ProjectMainDeleteModal.vue';
+import ProjectMainProjectGroupMoveModal from '@/services/project/v1/components/ProjectMainProjectGroupMoveModal.vue';
+import { useProjectPageStore } from '@/services/project/v1/stores/project-page-store';
+import { useProjectTreeStore } from '@/services/project/v1/stores/project-tree-store';
const gnbStore = useGnbStore();
diff --git a/apps/web/src/services/project/v-shared/stores/project-page-store.ts b/apps/web/src/services/project/v1/stores/project-page-store.ts
similarity index 98%
rename from apps/web/src/services/project/v-shared/stores/project-page-store.ts
rename to apps/web/src/services/project/v1/stores/project-page-store.ts
index e0419725b6..e9315e43f7 100644
--- a/apps/web/src/services/project/v-shared/stores/project-page-store.ts
+++ b/apps/web/src/services/project/v1/stores/project-page-store.ts
@@ -19,11 +19,10 @@ import { useUserStore } from '@/store/user/user-store';
import getRandomId from '@/lib/random-id-generator';
import ErrorHandler from '@/common/composables/error/errorHandler';
-
-import { useProjectTree } from '@/services/project/v-shared/composables/use-project-tree';
import type {
ProjectGroupTreeItem, ProjectGroupTreeNodeData, ProjectTreeNodeData, ProjectTreeRoot,
-} from '@/services/project/v-shared/types/project-tree-type';
+} from '@/common/modules/project/project-tree-type';
+import { useProjectTree } from '@/common/modules/project/use-project-tree';
const projectTreeHelper = useProjectTree();
diff --git a/apps/web/src/services/project/v-shared/stores/project-tree-store.ts b/apps/web/src/services/project/v1/stores/project-tree-store.ts
similarity index 89%
rename from apps/web/src/services/project/v-shared/stores/project-tree-store.ts
rename to apps/web/src/services/project/v1/stores/project-tree-store.ts
index ceff69d543..a70f413df6 100644
--- a/apps/web/src/services/project/v-shared/stores/project-tree-store.ts
+++ b/apps/web/src/services/project/v1/stores/project-tree-store.ts
@@ -3,7 +3,8 @@ import { nextTick, reactive } from 'vue';
import { cloneDeep } from 'lodash';
import { defineStore } from 'pinia';
-import type { TreeDisplayMap } from '@/services/project/v-shared/tree/type';
+import type { TreeDisplayMap } from '@cloudforet/mirinae/types/data-display/tree/tree-view/type';
+
export const useProjectTreeStore = defineStore('project-tree', () => {
const state = reactive({
diff --git a/apps/web/src/services/project/v2/ProjectContainer.vue b/apps/web/src/services/project/v2/ProjectContainer.vue
index 34675203ec..fe8bde8aac 100644
--- a/apps/web/src/services/project/v2/ProjectContainer.vue
+++ b/apps/web/src/services/project/v2/ProjectContainer.vue
@@ -1,89 +1,117 @@
-
+
-
+
-
@@ -91,20 +119,5 @@ onUnmounted(() => {
-
-
diff --git a/apps/web/src/services/project/v2/ProjectLSB.vue b/apps/web/src/services/project/v2/ProjectLSB.vue
index eaeee51e11..63833fe08c 100644
--- a/apps/web/src/services/project/v2/ProjectLSB.vue
+++ b/apps/web/src/services/project/v2/ProjectLSB.vue
@@ -1,256 +1,165 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ {{ $t('PROJECT.LANDING.ALL_PROJECTS') }}
+
+
-
-
-
-
- {{ $t('PROJECT.LANDING.SEARCH_EMPTY_TEXT') }}
-
-
+ {{ $t('COMMON.BUTTONS.CREATE') }}
+
+
-
-
-
+
+
+
+
+
+
-
diff --git a/apps/web/src/services/project/v2/components/ProjectActionDropdownButton.vue b/apps/web/src/services/project/v2/components/ProjectActionDropdownButton.vue
new file mode 100644
index 0000000000..80b88a933e
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectActionDropdownButton.vue
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectAndGroupListPanel.vue b/apps/web/src/services/project/v2/components/ProjectAndGroupListPanel.vue
new file mode 100644
index 0000000000..49ad1971d5
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectAndGroupListPanel.vue
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+ {{ $t('PROJECT.LADING.GROUPS_AND_PROJECTS') }}
+
+
+
+
+ {{ $t('PROJECT.LANDING.CREATE_GROUP') }}
+
+
+ {{ $t('PROJECT.LANDING.CREATE_PROJECT') }}
+
+
+
+
+
+
+
+ ({{ projectGroups.length }})
+
+
+
+
+
+
+
+ ({{ projects.length }})
+
+
+
+
+
+
+
{{ $t('PROJECT.LANDING.EMPTY_TEXT') }}
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectCard.vue b/apps/web/src/services/project/v2/components/ProjectCard.vue
new file mode 100644
index 0000000000..a9234fe57d
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectCard.vue
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+ {{ $t('PROJECT.LANDING.ADD_SERVICE_ACCOUNT') }}
+
+
+
+
+ {{ $t('PROJECT.LANDING.INVITE_ONLY') }}
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectDashboard.vue b/apps/web/src/services/project/v2/components/ProjectDashboard.vue
new file mode 100644
index 0000000000..694697630c
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectDashboard.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+ {{ dashboard?.name }}
+
+
beta
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectMainDeleteModal.vue b/apps/web/src/services/project/v2/components/ProjectDeleteModal.vue
similarity index 52%
rename from apps/web/src/services/project/v2/components/ProjectMainDeleteModal.vue
rename to apps/web/src/services/project/v2/components/ProjectDeleteModal.vue
index 648c36b598..a8fd0e7130 100644
--- a/apps/web/src/services/project/v2/components/ProjectMainDeleteModal.vue
+++ b/apps/web/src/services/project/v2/components/ProjectDeleteModal.vue
@@ -2,12 +2,11 @@
import {
computed, reactive,
} from 'vue';
-import { useRouter } from 'vue-router/composables';
-import { SpaceConnector } from '@cloudforet/core-lib/space-connector';
+import { useQueryClient } from '@tanstack/vue-query';
-import type { ProjectGroupDeleteParameters } from '@/api-clients/identity/project-group/schema/api-verbs/delete';
-import type { ProjectDeleteParameters } from '@/api-clients/identity/project/schema/api-verbs/delete';
+import { useProjectGroupApi } from '@/api-clients/identity/project-group/composables/use-project-group-api';
+import { useProjectApi } from '@/api-clients/identity/project/composables/use-project-api';
import { i18n as _i18n } from '@/translations';
import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store';
@@ -16,38 +15,29 @@ import { showSuccessMessage } from '@/lib/helper/notice-alert-helper';
import DeleteModal from '@/common/components/modals/DeleteModal.vue';
import ErrorHandler from '@/common/composables/error/errorHandler';
-import { useProxyValue } from '@/common/composables/proxy-state';
import { useFavoriteStore } from '@/common/modules/favorites/favorite-button/store/favorite-store';
import { FAVORITE_TYPE } from '@/common/modules/favorites/favorite-button/type';
import { useRecentStore } from '@/common/modules/navigations/stores/recent-store';
import { RECENT_TYPE } from '@/common/modules/navigations/type';
-import { PROJECT_ROUTE_V2 } from '@/services/project/v2/routes/route-constant';
+import { useProjectPageModalStore } from '@/services/project/v2/stores/project-page-modal-store';
-interface Props {
- visible: boolean;
- targetId: string;
- isProject?: boolean;
- skipRedirect?: boolean;
-}
+const emit = defineEmits(['deleted']);
-const props = defineProps();
-const emit = defineEmits<{(e: 'update:visible', value: boolean): void;
- (e: 'confirm'): void;
-}>();
+const projectPageModalStore = useProjectPageModalStore();
+const visible = computed(() => projectPageModalStore.state.deleteModalVisible && !!projectPageModalStore.state.targetId);
+const isProject = computed(() => projectPageModalStore.state.targetType === 'project');
-const router = useRouter();
const userWorkspaceStore = useUserWorkspaceStore();
const favoriteStore = useFavoriteStore();
const favoriteGetters = favoriteStore.getters;
const recentStore = useRecentStore();
const state = reactive({
- proxyVisible: useProxyValue('visible', props, emit),
currentWorkspaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId),
- title: computed(() => (props.isProject ? _i18n.t('PROJECT.DETAIL.MODAL_DELETE_PROJECT_TITLE') : _i18n.t('PROJECT.LANDING.MODAL_DELETE_PROJECT_GROUP.TITLE'))),
- content: computed(() => (props.isProject ? _i18n.t('PROJECT.DETAIL.MODAL_DELETE_PROJECT_CONTENT') : _i18n.t('PROJECT.LANDING.MODAL_DELETE_PROJECT_GROUP.CONTENT'))),
+ title: computed(() => (isProject.value ? _i18n.t('PROJECT.DETAIL.MODAL_DELETE_PROJECT_TITLE') : _i18n.t('PROJECT.LANDING.MODAL_DELETE_PROJECT_GROUP.TITLE'))),
+ content: computed(() => (isProject.value ? _i18n.t('PROJECT.DETAIL.MODAL_DELETE_PROJECT_CONTENT') : _i18n.t('PROJECT.LANDING.MODAL_DELETE_PROJECT_GROUP.CONTENT'))),
loading: false,
});
@@ -55,57 +45,61 @@ const handleConfirmDelete = async () => {
if (state.loading) return;
state.loading = true;
try {
- if (props.isProject) {
- await deleteProject();
+ if (!projectPageModalStore.state.targetId) throw new Error('No project or project group id');
+ if (projectPageModalStore.state.targetType === 'project') {
+ await deleteProject(projectPageModalStore.state.targetId);
} else {
- await deleteProjectGroup();
+ await deleteProjectGroup(projectPageModalStore.state.targetId);
}
- emit('confirm');
+ emit('deleted');
} catch (e) {
- if (props.isProject) ErrorHandler.handleRequestError(e, _i18n.t('PROJECT.DETAIL.ALT_E_DELETE_PROJECT'));
- else ErrorHandler.handleRequestError(e, _i18n.t('PROJECT.LANDING.ALT_E_DELETE_PROJECT_GROUP', { action: _i18n.t('PROJECT.LANDING.MODAL_DELETE_PROJECT_GROUP.TITLE') }));
+ if (projectPageModalStore.state.targetType === 'projectGroup') {
+ ErrorHandler.handleRequestError(e, _i18n.t('PROJECT.LANDING.ALT_E_DELETE_PROJECT_GROUP', { action: _i18n.t('PROJECT.LANDING.MODAL_DELETE_PROJECT_GROUP.TITLE') }), true);
+ } else {
+ ErrorHandler.handleRequestError(e, _i18n.t('PROJECT.DETAIL.ALT_E_DELETE_PROJECT'), true);
+ }
} finally {
state.loading = false;
- state.proxyVisible = false;
- if (!props.skipRedirect) {
- // TODO: Check route
- await router.replace({
- name: PROJECT_ROUTE_V2._NAME,
- });
- }
+ projectPageModalStore.closeDeleteModal();
}
};
-const deleteProject = async () => {
- await SpaceConnector.clientV2.identity.project.delete({
- project_id: props.targetId as string,
+const queryClient = useQueryClient();
+const { projectAPI, projectListQueryKey, projectQueryKey } = useProjectApi();
+const deleteProject = async (projectId: string) => {
+ await projectAPI.delete({
+ project_id: projectId,
});
+ queryClient.invalidateQueries({ queryKey: projectListQueryKey.value });
+ queryClient.removeQueries({ queryKey: [...projectQueryKey.value, projectId] });
await recentStore.deleteRecent({
type: RECENT_TYPE.PROJECT,
- itemId: props.targetId,
+ itemId: projectId,
});
showSuccessMessage(_i18n.t('PROJECT.DETAIL.ALT_S_DELETE_PROJECT'), '');
- const isFavoriteItem = favoriteGetters.projectItems.find((item) => item.itemId === props.targetId);
+ const isFavoriteItem = favoriteGetters.projectItems.find((item) => item.itemId === projectId);
if (isFavoriteItem) {
await favoriteStore.deleteFavorite({
itemType: FAVORITE_TYPE.PROJECT,
workspaceId: state.currentWorkspaceId || '',
- itemId: props.targetId as string,
+ itemId: projectId,
});
}
};
-
-const deleteProjectGroup = async () => {
- await SpaceConnector.clientV2.identity.projectGroup.delete({
- project_group_id: props.targetId,
+const { projectGroupAPI, projectGroupListQueryKey, projectGroupQueryKey } = useProjectGroupApi();
+const deleteProjectGroup = async (projectGroupId: string) => {
+ await projectGroupAPI.delete({
+ project_group_id: projectGroupId,
});
+ queryClient.invalidateQueries({ queryKey: projectGroupListQueryKey.value });
+ queryClient.removeQueries({ queryKey: [...projectGroupQueryKey.value, projectGroupId] });
showSuccessMessage(_i18n.t('PROJECT.LANDING.ALT_S_DELETE_PROJECT_GROUP'), '');
- const isFavoriteItem = favoriteGetters.projectGroupItems.find((item) => item.itemId === props.targetId);
+ const isFavoriteItem = favoriteGetters.projectGroupItems.find((item) => item.itemId === projectGroupId);
if (isFavoriteItem) {
await favoriteStore.deleteFavorite({
itemType: FAVORITE_TYPE.PROJECT_GROUP,
workspaceId: state.currentWorkspaceId || '',
- itemId: props.targetId,
+ itemId: projectGroupId,
});
}
};
@@ -114,14 +108,17 @@ const deleteProjectGroup = async () => {
{{ state.content }}
-
+import { computed, ref, watch } from 'vue';
+
+import { PTab } from '@cloudforet/mirinae';
+import type { TabItem } from '@cloudforet/mirinae/types/navigation/tabs/tab/type';
+
+import { useScopedQuery } from '@/api-clients/_common/composables/use-scoped-query';
+import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api';
+import type { PublicDashboardListParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/list';
+import { usePublicFolderApi } from '@/api-clients/dashboard/public-folder/composables/use-public-folder-api';
+import type { PublicFolderListParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/list';
+import { useServiceQueryKey } from '@/query/query-key/use-service-query-key';
+
+import ProjectDashboard from '@/services/project/v2/components/ProjectDashboard.vue';
+
+
+const props = defineProps<{
+ projectId: string,
+ dashboardId?: string,
+}>();
+const emit = defineEmits<{(e: 'update:dashboard-id', value?: string): void;}>();
+
+
+const activeTab = ref('overview');
+watch(() => props.dashboardId, (did) => {
+ activeTab.value = did ?? 'overview';
+}, { immediate: true });
+watch(() => props.projectId, () => {
+ activeTab.value = 'overview';
+});
+
+/* dashboard tabs */
+const { publicDashboardAPI } = usePublicDashboardApi();
+const { publicFolderAPI } = usePublicFolderApi();
+const { key: dashboardListQueryKey, params: dashboardListParams } = useServiceQueryKey('dashboard', 'public-dashboard', 'list', {
+ params: computed(() => ({
+ // project_id: props.id,
+ query: {
+ filter: [
+ { k: 'shared', v: true, o: 'eq' },
+ { k: 'version', v: '1.0', o: 'not' },
+ { k: 'scope', v: 'PROJECT', o: 'eq' },
+ ],
+ },
+ })),
+});
+const { data: dashboardList } = useScopedQuery({
+ queryKey: dashboardListQueryKey,
+ queryFn: () => publicDashboardAPI.list(dashboardListParams.value),
+ select: (data) => data?.results ?? [],
+ staleTime: 1000 * 60 * 5, // 5 minutes
+ gcTime: 1000 * 60 * 5, // 5 minutes
+});
+const { key: dashboardFolderListQueryKey, params: dashboardFolderListParams } = useServiceQueryKey('dashboard', 'public-folder', 'list', {
+ params: computed(() => ({
+ // project_id: props.id,
+ query: {
+ filter: [
+ { k: 'shared', v: true, o: 'eq' },
+ { k: 'scope', v: 'PROJECT', o: 'eq' },
+ ],
+ },
+ })),
+});
+const { data: dashboardFolderList } = useScopedQuery({
+ queryKey: dashboardFolderListQueryKey,
+ queryFn: () => publicFolderAPI.list(dashboardFolderListParams.value),
+ select: (data) => data?.results || [],
+ staleTime: 1000 * 60 * 5, // 5 minutes
+ gcTime: 1000 * 60 * 5, // 5 minutes
+});
+
+const tabs = computed(() => {
+ const folderTabs = dashboardFolderList.value?.map((folder) => ({
+ name: folder.folder_id,
+ label: folder.name,
+ tabType: 'folder',
+ icon: 'ic_folder',
+ subItems: dashboardList.value?.filter((dashboard) => dashboard.folder_id === folder.folder_id).map((dashboard) => ({
+ name: dashboard.dashboard_id,
+ label: dashboard.name,
+ icon: 'ic_service_dashboard',
+ })),
+ })) ?? [];
+ const dashboardTabs = dashboardList.value?.filter((dashboard) => !dashboard.folder_id).map((dashboard) => ({
+ name: dashboard.dashboard_id,
+ label: dashboard.name,
+ icon: 'ic_service_dashboard',
+ })) ?? [];
+ return [
+ { name: 'overview', label: 'Overview' }, // TODO: i18n
+ ...folderTabs,
+ ...dashboardTabs,
+ ];
+});
+
+const onChangeTab = (tab: string) => {
+ activeTab.value = tab;
+ emit('update:dashboard-id', tab === 'overview' ? undefined : tab);
+};
+
+
+
+
+
+
+
+
+ Overview will be implemented later.
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectFormModal.vue b/apps/web/src/services/project/v2/components/ProjectFormModal.vue
new file mode 100644
index 0000000000..e152e23376
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectFormModal.vue
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ state.selectedAccess === 'PRIVATE' ? $t('PROJECT.LANDING.ONLY_PEOPLE_INVITED') : $t('PROJECT.LANDING.EVERYONE_AT_THIS_WORKSPACE') }}
+
+ {{ $t('PROJECT.LANDING.CAN_ACCESS_TO_THIS_PROJECT') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectGroupCard.vue b/apps/web/src/services/project/v2/components/ProjectGroupCard.vue
new file mode 100644
index 0000000000..72c52a21b1
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectGroupCard.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+ {{ projectGroups.length }} {{ $t('PROJECT.LANDING.PROJECT_GROUPS') }} ⋅
+ {{ projects.length }} {{ $t('PROJECT.LANDING.PROJECTS') }}
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectGroupFormModal.vue b/apps/web/src/services/project/v2/components/ProjectGroupFormModal.vue
new file mode 100644
index 0000000000..991f36192c
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectGroupFormModal.vue
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectGroupMemberManagementModal.vue b/apps/web/src/services/project/v2/components/ProjectGroupMemberManagementModal.vue
new file mode 100644
index 0000000000..feebdfc712
--- /dev/null
+++ b/apps/web/src/services/project/v2/components/ProjectGroupMemberManagementModal.vue
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![role-type-icon]()
+
+ {{ userReferenceStore.getters.userItems[userId]?.label || userId }}
+ new
+
+
+
+
+ {{ getRoleName(userId) }}
+
+
+
+
+
+
+
+
+
+
+ Done
+
+
+
+
+
diff --git a/apps/web/src/services/project/v2/components/ProjectHeader.vue b/apps/web/src/services/project/v2/components/ProjectHeader.vue
index ca465c60a6..b299280a78 100644
--- a/apps/web/src/services/project/v2/components/ProjectHeader.vue
+++ b/apps/web/src/services/project/v2/components/ProjectHeader.vue
@@ -1,625 +1,142 @@
-