Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1db64827f | ||
|
|
8aa5cbccf3 | ||
|
|
cd146aa608 | ||
|
|
f82d4a9ead | ||
|
|
3f22642732 | ||
|
|
e339b7ad8f | ||
|
|
d4991b9a48 | ||
|
|
1bf683e044 | ||
|
|
807148671f | ||
|
|
d2b81ad2da | ||
|
|
3d14c9d9fe | ||
|
|
d7f40cf578 | ||
|
|
b370ef72ee | ||
|
|
0341205666 | ||
|
|
feab2b218d | ||
|
|
4acc5989dc | ||
|
|
a1b91a58a1 | ||
|
|
5fafdddb1e |
@@ -47,12 +47,6 @@ jobs:
|
||||
gh_buildx_version: ${{ steps.set_env_variables.outputs.BUILDX_VERSION }}
|
||||
gh_buildx_platforms: ${{ steps.set_env_variables.outputs.BUILDX_PLATFORMS }}
|
||||
gh_buildx_endpoint: ${{ steps.set_env_variables.outputs.BUILDX_ENDPOINT }}
|
||||
build_proxy: ${{ steps.changed_files.outputs.proxy_any_changed }}
|
||||
build_apiserver: ${{ steps.changed_files.outputs.apiserver_any_changed }}
|
||||
build_admin: ${{ steps.changed_files.outputs.admin_any_changed }}
|
||||
build_space: ${{ steps.changed_files.outputs.space_any_changed }}
|
||||
build_web: ${{ steps.changed_files.outputs.web_any_changed }}
|
||||
build_live: ${{ steps.changed_files.outputs.live_any_changed }}
|
||||
|
||||
dh_img_web: ${{ steps.set_env_variables.outputs.DH_IMG_WEB }}
|
||||
dh_img_space: ${{ steps.set_env_variables.outputs.DH_IMG_SPACE }}
|
||||
@@ -123,46 +117,7 @@ jobs:
|
||||
name: Checkout Files
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get changed files
|
||||
id: changed_files
|
||||
uses: tj-actions/changed-files@v42
|
||||
with:
|
||||
files_yaml: |
|
||||
apiserver:
|
||||
- apiserver/**
|
||||
proxy:
|
||||
- nginx/**
|
||||
admin:
|
||||
- admin/**
|
||||
- packages/**
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
- "tsconfig.json"
|
||||
- "turbo.json"
|
||||
space:
|
||||
- space/**
|
||||
- packages/**
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
- "tsconfig.json"
|
||||
- "turbo.json"
|
||||
web:
|
||||
- web/**
|
||||
- packages/**
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
- "tsconfig.json"
|
||||
- "turbo.json"
|
||||
live:
|
||||
- live/**
|
||||
- packages/**
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- 'tsconfig.json'
|
||||
- 'turbo.json'
|
||||
|
||||
branch_build_push_admin:
|
||||
if: ${{ needs.branch_build_setup.outputs.build_admin == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
|
||||
name: Build-Push Admin Docker Image
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [branch_build_setup]
|
||||
@@ -185,7 +140,6 @@ jobs:
|
||||
buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }}
|
||||
|
||||
branch_build_push_web:
|
||||
if: ${{ needs.branch_build_setup.outputs.build_web == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
|
||||
name: Build-Push Web Docker Image
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [branch_build_setup]
|
||||
@@ -208,7 +162,6 @@ jobs:
|
||||
buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }}
|
||||
|
||||
branch_build_push_space:
|
||||
if: ${{ needs.branch_build_setup.outputs.build_space == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
|
||||
name: Build-Push Space Docker Image
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [branch_build_setup]
|
||||
@@ -231,7 +184,6 @@ jobs:
|
||||
buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }}
|
||||
|
||||
branch_build_push_live:
|
||||
if: ${{ needs.branch_build_setup.outputs.build_live == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
|
||||
name: Build-Push Live Collaboration Docker Image
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [branch_build_setup]
|
||||
@@ -254,7 +206,6 @@ jobs:
|
||||
buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }}
|
||||
|
||||
branch_build_push_apiserver:
|
||||
if: ${{ needs.branch_build_setup.outputs.build_apiserver == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
|
||||
name: Build-Push API Server Docker Image
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [branch_build_setup]
|
||||
@@ -277,7 +228,6 @@ jobs:
|
||||
buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }}
|
||||
|
||||
branch_build_push_proxy:
|
||||
if: ${{ needs.branch_build_setup.outputs.build_proxy == 'true' || github.event_name == 'workflow_dispatch' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
|
||||
name: Build-Push Proxy Docker Image
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [branch_build_setup]
|
||||
|
||||
@@ -6,49 +6,9 @@ on:
|
||||
types: ["opened", "synchronize", "ready_for_review"]
|
||||
|
||||
jobs:
|
||||
get-changed-files:
|
||||
lint-apiserver:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
apiserver_changed: ${{ steps.changed-files.outputs.apiserver_any_changed }}
|
||||
admin_changed: ${{ steps.changed-files.outputs.admin_any_changed }}
|
||||
space_changed: ${{ steps.changed-files.outputs.space_any_changed }}
|
||||
web_changed: ${{ steps.changed-files.outputs.web_any_changed }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v44
|
||||
with:
|
||||
files_yaml: |
|
||||
apiserver:
|
||||
- apiserver/**
|
||||
admin:
|
||||
- admin/**
|
||||
- packages/**
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- 'tsconfig.json'
|
||||
- 'turbo.json'
|
||||
space:
|
||||
- space/**
|
||||
- packages/**
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- 'tsconfig.json'
|
||||
- 'turbo.json'
|
||||
web:
|
||||
- web/**
|
||||
- packages/**
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- 'tsconfig.json'
|
||||
- 'turbo.json'
|
||||
|
||||
lint-apiserver:
|
||||
needs: get-changed-files
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.get-changed-files.outputs.apiserver_changed == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
@@ -63,8 +23,7 @@ jobs:
|
||||
run: ruff check --fix apiserver
|
||||
|
||||
lint-admin:
|
||||
needs: get-changed-files
|
||||
if: needs.get-changed-files.outputs.admin_changed == 'true'
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -76,8 +35,7 @@ jobs:
|
||||
- run: yarn lint --filter=admin
|
||||
|
||||
lint-space:
|
||||
needs: get-changed-files
|
||||
if: needs.get-changed-files.outputs.space_changed == 'true'
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -89,8 +47,7 @@ jobs:
|
||||
- run: yarn lint --filter=space
|
||||
|
||||
lint-web:
|
||||
needs: get-changed-files
|
||||
if: needs.get-changed-files.outputs.web_changed == 'true'
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -34,6 +34,22 @@ class WorkspaceFavoriteEndpoint(BaseAPIView):
|
||||
def post(self, request, slug):
|
||||
try:
|
||||
workspace = Workspace.objects.get(slug=slug)
|
||||
|
||||
# If the favorite exists return
|
||||
if request.data.get("entity_identifier"):
|
||||
user_favorites = UserFavorite.objects.filter(
|
||||
workspace=workspace,
|
||||
user_id=request.user.id,
|
||||
entity_type=request.data.get("entity_type"),
|
||||
entity_identifier=request.data.get("entity_identifier"),
|
||||
).first()
|
||||
|
||||
# If the favorite exists return
|
||||
if user_favorites:
|
||||
serializer = UserFavoriteSerializer(user_favorites)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
# else create a new favorite
|
||||
serializer = UserFavoriteSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save(
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "concurrently \"babel src --out-dir dist --extensions '.ts,.js' --watch\" \"nodemon dist/server.js\"",
|
||||
"dev": "PORT=3100 concurrently \"babel src --out-dir dist --extensions '.ts,.js' --watch\" \"nodemon dist/server.js\"",
|
||||
"build": "babel src --out-dir dist --extensions \".ts,.js\"",
|
||||
"start": "node dist/server.js",
|
||||
"lint": "eslint src --ext .ts,.tsx",
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// icons
|
||||
import {
|
||||
TProjectAppliedDisplayFilterKeys,
|
||||
TProjectOrderByOptions,
|
||||
} from "@plane/types";
|
||||
import { TProjectAppliedDisplayFilterKeys, TProjectOrderByOptions } from "@plane/types";
|
||||
|
||||
export type TNetworkChoiceIconKey = "Lock" | "Globe2";
|
||||
|
||||
@@ -55,11 +52,11 @@ export const GROUP_CHOICES = {
|
||||
};
|
||||
|
||||
export const PROJECT_AUTOMATION_MONTHS = [
|
||||
{ i18n_label: "common.months_count", value: 1 },
|
||||
{ i18n_label: "common.months_count", value: 3 },
|
||||
{ i18n_label: "common.months_count", value: 6 },
|
||||
{ i18n_label: "common.months_count", value: 9 },
|
||||
{ i18n_label: "common.months_count", value: 12 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 1 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 3 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 6 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 9 },
|
||||
{ i18n_label: "workspace_projects.common.months_count", value: 12 },
|
||||
];
|
||||
|
||||
export const PROJECT_UNSPLASH_COVERS = [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TStaticViewTypes } from "@plane/types";
|
||||
import { TStaticViewTypes, IWorkspaceSearchResults } from "@plane/types";
|
||||
import { EUserWorkspaceRoles } from "./user";
|
||||
|
||||
export const ORGANIZATION_SIZE = [
|
||||
@@ -324,3 +324,15 @@ export const WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS_LINKS: IWorkspaceSidebarN
|
||||
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["inbox"],
|
||||
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["projects"],
|
||||
];
|
||||
|
||||
export const WORKSPACE_DEFAULT_SEARCH_RESULT: IWorkspaceSearchResults = {
|
||||
results: {
|
||||
workspace: [],
|
||||
project: [],
|
||||
issue: [],
|
||||
cycle: [],
|
||||
module: [],
|
||||
issue_view: [],
|
||||
page: [],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -130,7 +130,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => {
|
||||
CustomCodeInlineExtension,
|
||||
Markdown.configure({
|
||||
html: true,
|
||||
transformCopiedText: true,
|
||||
transformCopiedText: false,
|
||||
transformPastedText: true,
|
||||
breaks: true,
|
||||
}),
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { mergeAttributes } from "@tiptap/core";
|
||||
import Mention, { MentionOptions } from "@tiptap/extension-mention";
|
||||
import { MarkdownSerializerState } from "@tiptap/pm/markdown";
|
||||
import { Node as NodeType } from "@tiptap/pm/model";
|
||||
// types
|
||||
import { TMentionHandler } from "@/types";
|
||||
// local types
|
||||
import { EMentionComponentAttributeNames } from "./types";
|
||||
import { EMentionComponentAttributeNames, TMentionComponentAttributes } from "./types";
|
||||
|
||||
export type TMentionExtensionOptions = MentionOptions & {
|
||||
renderComponent: TMentionHandler["renderComponent"];
|
||||
getMentionedEntityDetails: TMentionHandler["getMentionedEntityDetails"];
|
||||
};
|
||||
|
||||
export const CustomMentionExtensionConfig = Mention.extend<TMentionExtensionOptions>({
|
||||
@@ -40,9 +43,26 @@ export const CustomMentionExtensionConfig = Mention.extend<TMentionExtensionOpti
|
||||
class: "mention",
|
||||
},
|
||||
|
||||
addStorage(this) {
|
||||
renderText({ node }) {
|
||||
return getMentionDisplayText(this.options, node);
|
||||
},
|
||||
|
||||
addStorage() {
|
||||
const options = this.options;
|
||||
return {
|
||||
mentionsOpen: false,
|
||||
markdown: {
|
||||
serialize(state: MarkdownSerializerState, node: NodeType) {
|
||||
state.write(getMentionDisplayText(options, node));
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
function getMentionDisplayText(options: TMentionExtensionOptions, node: NodeType): string {
|
||||
const attrs = node.attrs as TMentionComponentAttributes;
|
||||
const mentionEntityId = attrs[EMentionComponentAttributeNames.ENTITY_IDENTIFIER];
|
||||
const mentionEntityDetails = options.getMentionedEntityDetails?.(mentionEntityId ?? "");
|
||||
return `@${mentionEntityDetails?.display_name ?? attrs[EMentionComponentAttributeNames.ID] ?? mentionEntityId}`;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,13 @@ import { MentionNodeView } from "./mention-node-view";
|
||||
import { renderMentionsDropdown } from "./utils";
|
||||
|
||||
export const CustomMentionExtension = (props: TMentionHandler) => {
|
||||
const { searchCallback, renderComponent } = props;
|
||||
const { searchCallback, renderComponent, getMentionedEntityDetails } = props;
|
||||
return CustomMentionExtensionConfig.extend({
|
||||
addOptions(this) {
|
||||
return {
|
||||
...this.parent?.(),
|
||||
renderComponent,
|
||||
getMentionedEntityDetails,
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// plane types
|
||||
import { TSearchEntities } from "@plane/types";
|
||||
import { IUserLite, TSearchEntities } from "@plane/types";
|
||||
|
||||
export type TMentionSuggestion = {
|
||||
entity_identifier: string;
|
||||
@@ -20,6 +20,7 @@ export type TMentionComponentProps = Pick<TMentionSuggestion, "entity_identifier
|
||||
|
||||
export type TReadOnlyMentionHandler = {
|
||||
renderComponent: (props: TMentionComponentProps) => React.ReactNode;
|
||||
getMentionedEntityDetails?: (entity_identifier: string) => { display_name: string } | undefined;
|
||||
};
|
||||
|
||||
export type TMentionHandler = TReadOnlyMentionHandler & {
|
||||
|
||||
@@ -7,10 +7,16 @@ export const SUPPORTED_LANGUAGES: ILanguageOption[] = [
|
||||
{ label: "Français", value: "fr" },
|
||||
{ label: "Español", value: "es" },
|
||||
{ label: "日本語", value: "ja" },
|
||||
{ label: "中文", value: "zh-CN" },
|
||||
{ label: "简体中文", value: "zh-CN" },
|
||||
{ label: "繁體中文", value: "zh-TW" },
|
||||
{ label: "Русский", value: "ru" },
|
||||
{ label: "Italian", value: "it" },
|
||||
{ label: "Čeština", value: "cs" },
|
||||
{ label: "Slovenčina", value: "sk" },
|
||||
{ label: "Deutsch", value: "de" },
|
||||
{ label: "Українська", value: "ua" },
|
||||
{ label: "Polski", value: "pl" },
|
||||
{ label: "한국어", value: "ko" },
|
||||
];
|
||||
|
||||
export const STORAGE_KEY = "userLanguage";
|
||||
export const LANGUAGE_STORAGE_KEY = "userLanguage";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useContext } from 'react';
|
||||
import { useContext } from "react";
|
||||
// context
|
||||
import { TranslationContext } from '../context';
|
||||
import { TranslationContext } from "../context";
|
||||
// types
|
||||
import { ILanguageOption, TLanguage } from '../types';
|
||||
import { ILanguageOption, TLanguage } from "../types";
|
||||
|
||||
export type TTranslationStore = {
|
||||
t: (key: string, params?: Record<string, any>) => string;
|
||||
@@ -23,7 +23,7 @@ export type TTranslationStore = {
|
||||
export function useTranslation(): TTranslationStore {
|
||||
const store = useContext(TranslationContext);
|
||||
if (!store) {
|
||||
throw new Error('useTranslation must be used within a TranslationProvider');
|
||||
throw new Error("useTranslation must be used within a TranslationProvider");
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"home": "Domov",
|
||||
"your_work": "Vaše práce",
|
||||
"inbox": "Doručená pošta",
|
||||
"workspace": "workspace",
|
||||
"workspace": "Pracovní prostor",
|
||||
"views": "Pohledy",
|
||||
"analytics": "Analytika",
|
||||
"work_items": "Pracovní položky",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ import get from "lodash/get";
|
||||
import merge from "lodash/merge";
|
||||
import { makeAutoObservable, runInAction } from "mobx";
|
||||
// constants
|
||||
import { FALLBACK_LANGUAGE, SUPPORTED_LANGUAGES, STORAGE_KEY } from "../constants";
|
||||
import { FALLBACK_LANGUAGE, SUPPORTED_LANGUAGES, LANGUAGE_STORAGE_KEY } from "../constants";
|
||||
// core translations imports
|
||||
import coreEn from "../locales/en/core.json";
|
||||
// types
|
||||
@@ -48,14 +48,14 @@ export class TranslationStore {
|
||||
private initializeLanguage() {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
const savedLocale = localStorage.getItem(STORAGE_KEY) as TLanguage;
|
||||
const savedLocale = localStorage.getItem(LANGUAGE_STORAGE_KEY) as TLanguage;
|
||||
if (this.isValidLanguage(savedLocale)) {
|
||||
this.setLanguage(savedLocale);
|
||||
return;
|
||||
}
|
||||
|
||||
const browserLang = this.getBrowserLanguage();
|
||||
this.setLanguage(browserLang);
|
||||
// Fallback to default language
|
||||
this.setLanguage(FALLBACK_LANGUAGE);
|
||||
}
|
||||
|
||||
/** Loads the translations for the current language */
|
||||
@@ -147,12 +147,24 @@ export class TranslationStore {
|
||||
return import("../locales/ja/translations.json");
|
||||
case "zh-CN":
|
||||
return import("../locales/zh-CN/translations.json");
|
||||
case "zh-TW":
|
||||
return import("../locales/zh-TW/translations.json");
|
||||
case "ru":
|
||||
return import("../locales/ru/translations.json");
|
||||
case "it":
|
||||
return import("../locales/it/translations.json");
|
||||
case "cs":
|
||||
return import("../locales/cs/translations.json");
|
||||
case "sk":
|
||||
return import("../locales/sk/translations.json");
|
||||
case "de":
|
||||
return import("../locales/de/translations.json");
|
||||
case "ua":
|
||||
return import("../locales/ua/translations.json");
|
||||
case "pl":
|
||||
return import("../locales/pl/translations.json");
|
||||
case "ko":
|
||||
return import("../locales/ko/translations.json");
|
||||
default:
|
||||
throw new Error(`Unsupported language: ${language}`);
|
||||
}
|
||||
@@ -163,40 +175,6 @@ export class TranslationStore {
|
||||
return lang !== null && this.availableLanguages.some((l) => l.value === lang);
|
||||
}
|
||||
|
||||
/** Checks if a language code is similar to any supported language */
|
||||
private findSimilarLanguage(lang: string): TLanguage | null {
|
||||
// Convert to lowercase for case-insensitive comparison
|
||||
const normalizedLang = lang.toLowerCase();
|
||||
|
||||
// Find a supported language that includes or is included in the browser language
|
||||
const similarLang = this.availableLanguages.find(
|
||||
(l) => normalizedLang.includes(l.value.toLowerCase()) || l.value.toLowerCase().includes(normalizedLang)
|
||||
);
|
||||
|
||||
return similarLang ? similarLang.value : null;
|
||||
}
|
||||
|
||||
/** Gets the browser language based on the navigator.language */
|
||||
private getBrowserLanguage(): TLanguage {
|
||||
const browserLang = navigator.language;
|
||||
|
||||
// Check exact match first
|
||||
if (this.isValidLanguage(browserLang)) {
|
||||
return browserLang;
|
||||
}
|
||||
|
||||
// Check base language without region code
|
||||
const baseLang = browserLang.split("-")[0];
|
||||
if (this.isValidLanguage(baseLang)) {
|
||||
return baseLang as TLanguage;
|
||||
}
|
||||
|
||||
// Try to find a similar language
|
||||
const similarLang = this.findSimilarLanguage(browserLang) || this.findSimilarLanguage(baseLang);
|
||||
|
||||
return similarLang || FALLBACK_LANGUAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache key for the given key and locale
|
||||
* @param key - the key to get the cache key for
|
||||
@@ -281,7 +259,7 @@ export class TranslationStore {
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem(STORAGE_KEY, lng);
|
||||
localStorage.setItem(LANGUAGE_STORAGE_KEY, lng);
|
||||
document.documentElement.lang = lng;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type TLanguage = "en" | "fr" | "es" | "ja" | "zh-CN" | "ru" | "it" | "cs";
|
||||
export type TLanguage = "en" | "fr" | "es" | "ja" | "zh-CN" | "zh-TW" | "ru" | "it" | "cs" | "sk" | "de" | "ua" | "pl" | "ko";
|
||||
|
||||
export interface ILanguageOption {
|
||||
label: string;
|
||||
|
||||
@@ -7,6 +7,8 @@ import { EditorMentionsRoot } from "@/components/editor";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
|
||||
type LiteTextReadOnlyEditorWrapperProps = MakeOptional<
|
||||
Omit<ILiteTextReadOnlyEditor, "fileHandler" | "mentionHandler">,
|
||||
@@ -17,22 +19,29 @@ type LiteTextReadOnlyEditorWrapperProps = MakeOptional<
|
||||
};
|
||||
|
||||
export const LiteTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, LiteTextReadOnlyEditorWrapperProps>(
|
||||
({ anchor, workspaceId, disabledExtensions, ...props }, ref) => (
|
||||
<LiteTextReadOnlyEditorWithRef
|
||||
ref={ref}
|
||||
disabledExtensions={disabledExtensions ?? []}
|
||||
fileHandler={getReadOnlyEditorFileHandlers({
|
||||
anchor,
|
||||
workspaceId,
|
||||
})}
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
}}
|
||||
{...props}
|
||||
// overriding the customClassName to add relative class passed
|
||||
containerClassName={cn(props.containerClassName, "relative p-2")}
|
||||
/>
|
||||
)
|
||||
({ anchor, workspaceId, disabledExtensions, ...props }, ref) => {
|
||||
const { getMemberById } = useMember();
|
||||
|
||||
return (
|
||||
<LiteTextReadOnlyEditorWithRef
|
||||
ref={ref}
|
||||
disabledExtensions={disabledExtensions ?? []}
|
||||
fileHandler={getReadOnlyEditorFileHandlers({
|
||||
anchor,
|
||||
workspaceId,
|
||||
})}
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({
|
||||
display_name: getMemberById(id)?.member__display_name ?? "",
|
||||
}),
|
||||
}}
|
||||
{...props}
|
||||
// overriding the customClassName to add relative class passed
|
||||
containerClassName={cn(props.containerClassName, "relative p-2")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
LiteTextReadOnlyEditor.displayName = "LiteTextReadOnlyEditor";
|
||||
|
||||
@@ -6,6 +6,8 @@ import { MakeOptional } from "@plane/types";
|
||||
import { EditorMentionsRoot } from "@/components/editor";
|
||||
// helpers
|
||||
import { getEditorFileHandlers } from "@/helpers/editor.helper";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
|
||||
interface RichTextEditorWrapperProps
|
||||
extends MakeOptional<Omit<IRichTextEditor, "fileHandler" | "mentionHandler">, "disabledExtensions"> {
|
||||
@@ -16,11 +18,14 @@ interface RichTextEditorWrapperProps
|
||||
|
||||
export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProps>((props, ref) => {
|
||||
const { anchor, containerClassName, uploadFile, workspaceId, disabledExtensions, ...rest } = props;
|
||||
|
||||
const { getMemberById } = useMember();
|
||||
return (
|
||||
<RichTextEditorWithRef
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({
|
||||
display_name: getMemberById(id)?.member__display_name ?? "",
|
||||
}),
|
||||
}}
|
||||
ref={ref}
|
||||
disabledExtensions={disabledExtensions ?? []}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { EditorMentionsRoot } from "@/components/editor";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
|
||||
type RichTextReadOnlyEditorWrapperProps = MakeOptional<
|
||||
Omit<IRichTextReadOnlyEditor, "fileHandler" | "mentionHandler">,
|
||||
@@ -17,22 +19,29 @@ type RichTextReadOnlyEditorWrapperProps = MakeOptional<
|
||||
};
|
||||
|
||||
export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, RichTextReadOnlyEditorWrapperProps>(
|
||||
({ anchor, workspaceId, disabledExtensions, ...props }, ref) => (
|
||||
<RichTextReadOnlyEditorWithRef
|
||||
ref={ref}
|
||||
disabledExtensions={disabledExtensions ?? []}
|
||||
fileHandler={getReadOnlyEditorFileHandlers({
|
||||
anchor,
|
||||
workspaceId,
|
||||
})}
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
}}
|
||||
{...props}
|
||||
// overriding the customClassName to add relative class passed
|
||||
containerClassName={cn("relative p-0 border-none", props.containerClassName)}
|
||||
/>
|
||||
)
|
||||
({ anchor, workspaceId, disabledExtensions, ...props }, ref) => {
|
||||
const { getMemberById } = useMember();
|
||||
|
||||
return (
|
||||
<RichTextReadOnlyEditorWithRef
|
||||
ref={ref}
|
||||
disabledExtensions={disabledExtensions ?? []}
|
||||
fileHandler={getReadOnlyEditorFileHandlers({
|
||||
anchor,
|
||||
workspaceId,
|
||||
})}
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({
|
||||
display_name: getMemberById(id)?.member__display_name ?? "",
|
||||
}),
|
||||
}}
|
||||
{...props}
|
||||
// overriding the customClassName to add relative class passed
|
||||
containerClassName={cn("relative p-0 border-none", props.containerClassName)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
RichTextReadOnlyEditor.displayName = "RichTextReadOnlyEditor";
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ const ProjectCyclesPage = observer(() => {
|
||||
// derived values
|
||||
const totalCycles = currentProjectCycleIds?.length ?? 0;
|
||||
const project = projectId ? getProjectById(projectId?.toString()) : undefined;
|
||||
const pageTitle = project?.name ? `${project?.name} - ${t("cycles.label", { count: 2 })}` : undefined;
|
||||
const pageTitle = project?.name ? `${project?.name} - ${t("common.cycles", { count: 2 })}` : undefined;
|
||||
const hasAdminLevelPermission = allowPermissions([EUserProjectRoles.ADMIN], EUserPermissionsLevel.PROJECT);
|
||||
const hasMemberLevelPermission = allowPermissions(
|
||||
[EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER],
|
||||
|
||||
+4
-2
@@ -16,14 +16,16 @@ import { generateWorkItemLink } from "@/helpers/issue.helper";
|
||||
// plane web components
|
||||
import { IssueIdentifier } from "@/plane-web/components/issues";
|
||||
|
||||
export const commandGroups: {
|
||||
export type TCommandGroups = {
|
||||
[key: string]: {
|
||||
icon: JSX.Element | null;
|
||||
itemName: (item: any) => React.ReactNode;
|
||||
path: (item: any, projectId: string | undefined) => string;
|
||||
title: string;
|
||||
};
|
||||
} = {
|
||||
};
|
||||
|
||||
export const commandGroups: TCommandGroups = {
|
||||
cycle: {
|
||||
icon: <ContrastIcon className="h-3 w-3" />,
|
||||
itemName: (cycle: IWorkspaceDefaultSearchResult) => (
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./actions";
|
||||
export * from "./modals";
|
||||
export * from "./helpers";
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./values";
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./update";
|
||||
@@ -1,12 +0,0 @@
|
||||
import { TIssueServiceType } from "@plane/types";
|
||||
|
||||
export type TIssueAdditionalPropertyValuesUpdateProps = {
|
||||
issueId: string;
|
||||
issueTypeId: string;
|
||||
projectId: string;
|
||||
workspaceSlug: string;
|
||||
isDisabled: boolean;
|
||||
issueServiceType?: TIssueServiceType;
|
||||
};
|
||||
|
||||
export const IssueAdditionalPropertyValuesUpdate: React.FC<TIssueAdditionalPropertyValuesUpdateProps> = () => <></>;
|
||||
@@ -0,0 +1,13 @@
|
||||
import React, { FC } from "react";
|
||||
// plane imports
|
||||
|
||||
export type TWorkItemAdditionalSidebarProperties = {
|
||||
workItemId: string;
|
||||
workItemTypeId: string | null;
|
||||
projectId: string;
|
||||
workspaceSlug: string;
|
||||
isEditable: boolean;
|
||||
isPeekView?: boolean;
|
||||
};
|
||||
|
||||
export const WorkItemAdditionalSidebarProperties: FC<TWorkItemAdditionalSidebarProperties> = () => <></>;
|
||||
@@ -1,5 +1,7 @@
|
||||
// types
|
||||
import { IIssueDisplayProperties } from "@plane/types";
|
||||
// lib
|
||||
import { store } from "@/lib/store-context";
|
||||
|
||||
export type TShouldRenderDisplayProperty = {
|
||||
workspaceSlug: string;
|
||||
@@ -16,3 +18,13 @@ export const shouldRenderDisplayProperty = (props: TShouldRenderDisplayProperty)
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
export const shouldRenderColumn = (key: keyof IIssueDisplayProperties): boolean => {
|
||||
const isEstimateEnabled: boolean = store.projectRoot.project.currentProjectDetails?.estimate !== null;
|
||||
switch (key) {
|
||||
case "estimate":
|
||||
return isEstimateEnabled;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { TIssue } from "@plane/types";
|
||||
import { getIssueIds } from "@/store/issue/helpers/base-issues-utils";
|
||||
|
||||
export const workItemSortWithOrderByExtended = (array: TIssue[], key?: string) => getIssueIds(array);
|
||||
@@ -97,7 +97,7 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
|
||||
<>
|
||||
{PROJECT_AUTOMATION_MONTHS.map((month) => (
|
||||
<CustomSelect.Option key={month.i18n_label} value={month.value}>
|
||||
<span className="text-sm">{t(month.i18n_label, { month: month.value })}</span>
|
||||
<span className="text-sm">{t(month.i18n_label, { months: month.value })}</span>
|
||||
</CustomSelect.Option>
|
||||
))}
|
||||
|
||||
@@ -106,7 +106,7 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
|
||||
className="flex w-full select-none items-center rounded px-1 py-1.5 text-sm text-custom-text-200 hover:bg-custom-background-80"
|
||||
onClick={() => setmonthModal(true)}
|
||||
>
|
||||
{t("customize_time_range")}
|
||||
{t("common.customize_time_range")}
|
||||
</button>
|
||||
</>
|
||||
</CustomSelect>
|
||||
|
||||
@@ -124,7 +124,7 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
||||
<>
|
||||
{PROJECT_AUTOMATION_MONTHS.map((month) => (
|
||||
<CustomSelect.Option key={month.i18n_label} value={month.value}>
|
||||
{t(month.i18n_label, { month: month.value })}
|
||||
{t(month.i18n_label, { months: month.value })}
|
||||
</CustomSelect.Option>
|
||||
))}
|
||||
<button
|
||||
@@ -132,7 +132,7 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
||||
className="flex w-full select-none items-center rounded px-1 py-1.5 text-custom-text-200 hover:bg-custom-background-80"
|
||||
onClick={() => setmonthModal(true)}
|
||||
>
|
||||
{t("customize_time_range")}
|
||||
{t("common.customize_time_range")}
|
||||
</button>
|
||||
</>
|
||||
</CustomSelect>
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
import { Command } from "cmdk";
|
||||
import { useParams } from "next/navigation";
|
||||
// types
|
||||
// plane imports
|
||||
import { IWorkspaceSearchResults } from "@plane/types";
|
||||
// helpers
|
||||
import { commandGroups } from "@/components/command-palette";
|
||||
// hooks
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
// plane web imports
|
||||
import { commandGroups } from "@/plane-web/components/command-palette";
|
||||
|
||||
type Props = {
|
||||
closePalette: () => void;
|
||||
@@ -25,9 +25,9 @@ export const CommandPaletteSearchResults: React.FC<Props> = (props) => {
|
||||
return (
|
||||
<>
|
||||
{Object.keys(results.results).map((key) => {
|
||||
// TODO: add type for results
|
||||
const section = (results.results as any)[key];
|
||||
const currentSection = commandGroups[key];
|
||||
|
||||
if (!currentSection) return null;
|
||||
if (section.length > 0) {
|
||||
return (
|
||||
|
||||
@@ -8,7 +8,7 @@ import useSWR from "swr";
|
||||
import { CommandIcon, FolderPlus, Search, Settings, X } from "lucide-react";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { EUserPermissions, EUserPermissionsLevel, WORKSPACE_DEFAULT_SEARCH_RESULT } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { IWorkspaceSearchResults } from "@plane/types";
|
||||
import { LayersIcon, Loader, ToggleSwitch } from "@plane/ui";
|
||||
@@ -58,9 +58,7 @@ export const CommandModal: React.FC = observer(() => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isSearching, setIsSearching] = useState(false);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [results, setResults] = useState<IWorkspaceSearchResults>({
|
||||
results: { workspace: [], project: [], issue: [], cycle: [], module: [], issue_view: [], page: [] },
|
||||
});
|
||||
const [results, setResults] = useState<IWorkspaceSearchResults>(WORKSPACE_DEFAULT_SEARCH_RESULT);
|
||||
const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false);
|
||||
const [pages, setPages] = useState<string[]>([]);
|
||||
const [searchInIssue, setSearchInIssue] = useState(false);
|
||||
@@ -151,9 +149,7 @@ export const CommandModal: React.FC = observer(() => {
|
||||
setIsSearching(false);
|
||||
});
|
||||
} else {
|
||||
setResults({
|
||||
results: { workspace: [], project: [], issue: [], cycle: [], module: [], issue_view: [], page: [] },
|
||||
});
|
||||
setResults(WORKSPACE_DEFAULT_SEARCH_RESULT);
|
||||
setIsLoading(false);
|
||||
setIsSearching(false);
|
||||
}
|
||||
|
||||
@@ -2,4 +2,3 @@ export * from "./actions";
|
||||
export * from "./shortcuts-modal";
|
||||
export * from "./command-modal";
|
||||
export * from "./command-palette";
|
||||
export * from "./helpers";
|
||||
|
||||
@@ -13,6 +13,8 @@ import { cn } from "@/helpers/common.helper";
|
||||
import { isCommentEmpty } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { useEditorConfig, useEditorMention } from "@/hooks/editor";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
||||
// plane web services
|
||||
@@ -57,6 +59,8 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
|
||||
const [isFocused, setIsFocused] = useState(showToolbarInitially);
|
||||
// editor flaggings
|
||||
const { liteTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString());
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
// use editor mention
|
||||
const { fetchMentions } = useEditorMention({
|
||||
searchEntity: async (payload) =>
|
||||
@@ -97,6 +101,7 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
|
||||
return res;
|
||||
},
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }),
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
containerClassName={cn(containerClassName, "relative")}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { EditorMentionsRoot } from "@/components/editor";
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useEditorConfig } from "@/hooks/editor";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
||||
|
||||
@@ -22,6 +24,9 @@ type LiteTextReadOnlyEditorWrapperProps = MakeOptional<
|
||||
|
||||
export const LiteTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, LiteTextReadOnlyEditorWrapperProps>(
|
||||
({ workspaceId, workspaceSlug, projectId, disabledExtensions: additionalDisabledExtensions, ...props }, ref) => {
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
|
||||
// editor flaggings
|
||||
const { liteTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString());
|
||||
// editor config
|
||||
@@ -38,6 +43,7 @@ export const LiteTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, Lit
|
||||
})}
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }),
|
||||
}}
|
||||
{...props}
|
||||
// overriding the containerClassName to add relative class passed
|
||||
|
||||
@@ -8,6 +8,8 @@ import { EditorMentionsRoot } from "@/components/editor";
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useEditorConfig, useEditorMention } from "@/hooks/editor";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
||||
|
||||
@@ -31,6 +33,8 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
|
||||
disabledExtensions: additionalDisabledExtensions,
|
||||
...rest
|
||||
} = props;
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
// editor flaggings
|
||||
const { richTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString());
|
||||
// use editor mention
|
||||
@@ -57,6 +61,7 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
|
||||
return res;
|
||||
},
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }),
|
||||
}}
|
||||
{...rest}
|
||||
containerClassName={cn("relative pl-3 pb-3", containerClassName)}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { EditorMentionsRoot } from "@/components/editor";
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useEditorConfig } from "@/hooks/editor";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
||||
|
||||
@@ -22,6 +24,9 @@ type RichTextReadOnlyEditorWrapperProps = MakeOptional<
|
||||
|
||||
export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, RichTextReadOnlyEditorWrapperProps>(
|
||||
({ workspaceId, workspaceSlug, projectId, disabledExtensions: additionalDisabledExtensions, ...props }, ref) => {
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
|
||||
// editor flaggings
|
||||
const { richTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString());
|
||||
// editor config
|
||||
@@ -38,6 +43,7 @@ export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, Ric
|
||||
})}
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }),
|
||||
}}
|
||||
{...props}
|
||||
// overriding the containerClassName to add relative class passed
|
||||
|
||||
@@ -371,7 +371,7 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="fixed right-0 z-[5] h-full w-full min-w-[300px] overflow-hidden border-l border-custom-border-200 bg-custom-sidebar-background-100 py-5 sm:w-1/2 md:relative md:w-1/3 lg:min-w-80 xl:min-w-96"
|
||||
className="fixed right-0 z-[5] h-full w-full min-w-[300px] border-l border-custom-border-200 bg-custom-sidebar-background-100 py-5 sm:w-1/2 md:relative md:w-1/3 lg:min-w-80 xl:min-w-96"
|
||||
style={issueDetailSidebarCollapsed ? { right: `-${window?.innerWidth || 0}px` } : {}}
|
||||
>
|
||||
<IssueDetailsSidebar
|
||||
|
||||
@@ -24,9 +24,9 @@ import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
||||
// hooks
|
||||
import { useProjectEstimates, useIssueDetail, useProject, useProjectState, useMember } from "@/hooks/store";
|
||||
// plane web components
|
||||
import { IssueAdditionalPropertyValuesUpdate } from "@/plane-web/components/issue-types/values";
|
||||
import { IssueParentSelectRoot, IssueWorklogProperty } from "@/plane-web/components/issues";
|
||||
// components
|
||||
import { WorkItemAdditionalSidebarProperties } from "@/plane-web/components/issues/issue-details/additional-properties";
|
||||
import type { TIssueOperations } from "./root";
|
||||
|
||||
type Props = {
|
||||
@@ -293,15 +293,14 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
disabled={!isEditable}
|
||||
/>
|
||||
|
||||
{issue.type_id && (
|
||||
<IssueAdditionalPropertyValuesUpdate
|
||||
issueId={issueId}
|
||||
issueTypeId={issue.type_id}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
isDisabled={!isEditable}
|
||||
/>
|
||||
)}
|
||||
<WorkItemAdditionalSidebarProperties
|
||||
workItemId={issue.id}
|
||||
workItemTypeId={issue.type_id}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
isEditable={isEditable}
|
||||
isPeekView
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { IIssueDisplayProperties, TIssue } from "@plane/types";
|
||||
import { useEventTracker } from "@/hooks/store";
|
||||
// components
|
||||
import { SPREADSHEET_COLUMNS } from "@/plane-web/components/issues/issue-layouts/utils";
|
||||
import { shouldRenderColumn } from "@/plane-web/helpers/issue-filter.helper";
|
||||
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
|
||||
// utils
|
||||
|
||||
@@ -20,13 +21,13 @@ type Props = {
|
||||
};
|
||||
|
||||
export const IssueColumn = observer((props: Props) => {
|
||||
const { displayProperties, issueDetail, disableUserActions, property, updateIssue, isEstimateEnabled } = props;
|
||||
const { displayProperties, issueDetail, disableUserActions, property, updateIssue } = props;
|
||||
// router
|
||||
const pathname = usePathname();
|
||||
const tableCellRef = useRef<HTMLTableCellElement | null>(null);
|
||||
const { captureIssueEvent } = useEventTracker();
|
||||
|
||||
const shouldRenderProperty = property === "estimate" ? isEstimateEnabled : true;
|
||||
const shouldRenderProperty = shouldRenderColumn(property);
|
||||
|
||||
const Column = SPREADSHEET_COLUMNS[property];
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useRef } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@plane/types";
|
||||
//components
|
||||
import { shouldRenderColumn } from "@/plane-web/helpers/issue-filter.helper";
|
||||
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
|
||||
import { HeaderColumn } from "./columns/header-column";
|
||||
|
||||
@@ -15,19 +16,12 @@ interface Props {
|
||||
isEpic?: boolean;
|
||||
}
|
||||
export const SpreadsheetHeaderColumn = observer((props: Props) => {
|
||||
const {
|
||||
displayProperties,
|
||||
displayFilters,
|
||||
property,
|
||||
isEstimateEnabled,
|
||||
handleDisplayFilterUpdate,
|
||||
isEpic = false,
|
||||
} = props;
|
||||
const { displayProperties, displayFilters, property, handleDisplayFilterUpdate, isEpic = false } = props;
|
||||
|
||||
//hooks
|
||||
const tableHeaderCellRef = useRef<HTMLTableCellElement | null>(null);
|
||||
|
||||
const shouldRenderProperty = property === "estimate" ? isEstimateEnabled : true;
|
||||
const shouldRenderProperty = shouldRenderColumn(property);
|
||||
|
||||
return (
|
||||
<WithDisplayPropertiesHOC
|
||||
|
||||
@@ -23,8 +23,8 @@ import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper"
|
||||
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
||||
import { useIssueDetail, useMember, useProject, useProjectState } from "@/hooks/store";
|
||||
// plane web components
|
||||
import { IssueAdditionalPropertyValuesUpdate } from "@/plane-web/components/issue-types/values";
|
||||
import { IssueParentSelectRoot, IssueWorklogProperty } from "@/plane-web/components/issues";
|
||||
import { WorkItemAdditionalSidebarProperties } from "@/plane-web/components/issues/issue-details/additional-properties";
|
||||
|
||||
interface IPeekOverviewProperties {
|
||||
workspaceSlug: string;
|
||||
@@ -291,15 +291,14 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
{issue.type_id && (
|
||||
<IssueAdditionalPropertyValuesUpdate
|
||||
issueId={issueId}
|
||||
issueTypeId={issue.type_id}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
isDisabled={disabled}
|
||||
/>
|
||||
)}
|
||||
<WorkItemAdditionalSidebarProperties
|
||||
workItemId={issue.id}
|
||||
workItemTypeId={issue.type_id}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
isEditable={!disabled}
|
||||
isPeekView
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -90,20 +90,17 @@ export const ModulesListView: React.FC = observer(() => {
|
||||
|
||||
return (
|
||||
<ContentWrapper variant={ERowVariant.HUGGING}>
|
||||
{displayFilters?.layout === "list" && (
|
||||
<div className="flex h-full w-full justify-between">
|
||||
<div className="size-full flex justify-between">
|
||||
{displayFilters?.layout === "list" && (
|
||||
<ListLayout>
|
||||
{filteredModuleIds.map((moduleId) => (
|
||||
<ModuleListItem key={moduleId} moduleId={moduleId} />
|
||||
))}
|
||||
</ListLayout>
|
||||
<ModulePeekOverview projectId={projectId?.toString() ?? ""} workspaceSlug={workspaceSlug?.toString() ?? ""} />
|
||||
</div>
|
||||
)}
|
||||
{displayFilters?.layout === "board" && (
|
||||
<Row className="flex h-full w-full justify-between py-page-y">
|
||||
<div
|
||||
className={`grid h-full w-full grid-cols-1 gap-6 overflow-y-auto ${
|
||||
)}
|
||||
{displayFilters?.layout === "board" && (
|
||||
<Row
|
||||
className={`size-full py-page-y grid grid-cols-1 gap-6 overflow-y-auto ${
|
||||
peekModule
|
||||
? "lg:grid-cols-1 xl:grid-cols-2 3xl:grid-cols-3"
|
||||
: "lg:grid-cols-2 xl:grid-cols-3 3xl:grid-cols-4"
|
||||
@@ -112,11 +109,17 @@ export const ModulesListView: React.FC = observer(() => {
|
||||
{filteredModuleIds.map((moduleId) => (
|
||||
<ModuleCardItem key={moduleId} moduleId={moduleId} />
|
||||
))}
|
||||
</Row>
|
||||
)}
|
||||
{displayFilters?.layout === "gantt" && (
|
||||
<div className="size-full overflow-hidden">
|
||||
<ModulesListGanttChartView />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-shrink-0">
|
||||
<ModulePeekOverview projectId={projectId?.toString() ?? ""} workspaceSlug={workspaceSlug?.toString() ?? ""} />
|
||||
</Row>
|
||||
)}
|
||||
{displayFilters?.layout === "gantt" && <ModulesListGanttChartView />}
|
||||
</div>
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ import { cn, LIVE_BASE_PATH, LIVE_BASE_URL } from "@/helpers/common.helper";
|
||||
import { generateRandomColor } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { useEditorMention } from "@/hooks/editor";
|
||||
import { useUser, useWorkspace } from "@/hooks/store";
|
||||
import { useUser, useWorkspace, useMember } from "@/hooks/store";
|
||||
import { usePageFilters } from "@/hooks/use-page-filters";
|
||||
// plane web components
|
||||
import { EditorAIMenu } from "@/plane-web/components/pages";
|
||||
@@ -68,6 +68,8 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
// store hooks
|
||||
const { data: currentUser } = useUser();
|
||||
const { getWorkspaceBySlug } = useWorkspace();
|
||||
const { getUserDetails } = useMember();
|
||||
|
||||
// derived values
|
||||
const { id: pageId, name: pageTitle, isContentEditable, updateTitle } = page;
|
||||
const workspaceId = getWorkspaceBySlug(workspaceSlug)?.id ?? "";
|
||||
@@ -192,6 +194,7 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
return res;
|
||||
},
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }),
|
||||
}}
|
||||
embedHandler={{
|
||||
issue: issueEmbedProps,
|
||||
|
||||
@@ -12,6 +12,8 @@ import { EditorMentionsRoot } from "@/components/editor";
|
||||
import { useEditorConfig } from "@/hooks/editor";
|
||||
import { useWorkspace } from "@/hooks/store";
|
||||
import { usePageFilters } from "@/hooks/use-page-filters";
|
||||
// store hooks
|
||||
import { useMember } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
||||
import { useIssueEmbed } from "@/plane-web/hooks/use-issue-embed";
|
||||
@@ -25,6 +27,8 @@ export type TVersionEditorProps = {
|
||||
|
||||
export const PagesVersionEditor: React.FC<TVersionEditorProps> = observer((props) => {
|
||||
const { activeVersion, currentVersionDescription, isCurrentVersionActive, versionDetails } = props;
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
// params
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// store hooks
|
||||
@@ -108,6 +112,7 @@ export const PagesVersionEditor: React.FC<TVersionEditorProps> = observer((props
|
||||
})}
|
||||
mentionHandler={{
|
||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
||||
getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }),
|
||||
}}
|
||||
embedHandler={{
|
||||
issue: {
|
||||
|
||||
@@ -111,9 +111,10 @@ export class FavoriteStore implements IFavoriteStore {
|
||||
* @returns Promise<IFavorite>
|
||||
*/
|
||||
addFavorite = async (workspaceSlug: string, data: Partial<IFavorite>) => {
|
||||
const id = uuidv4();
|
||||
data = { ...data, parent: null, is_folder: data.entity_type === "folder" };
|
||||
|
||||
if (data.entity_identifier && this.entityMap[data.entity_identifier]) return this.entityMap[data.entity_identifier];
|
||||
const id = uuidv4();
|
||||
try {
|
||||
// optimistic addition
|
||||
runInAction(() => {
|
||||
@@ -271,6 +272,7 @@ export class FavoriteStore implements IFavoriteStore {
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
deleteFavorite = async (workspaceSlug: string, favoriteId: string) => {
|
||||
if (!this.favoriteMap[favoriteId]) return;
|
||||
const parent = this.favoriteMap[favoriteId].parent;
|
||||
const children = this.groupedFavorites[favoriteId].children;
|
||||
const entity_identifier = this.favoriteMap[favoriteId].entity_identifier;
|
||||
|
||||
@@ -37,6 +37,7 @@ import { convertToISODateString } from "@/helpers/date-time.helper";
|
||||
// local-db
|
||||
import { SPECIAL_ORDER_BY } from "@/local-db/utils/query-constructor";
|
||||
import { updatePersistentLayer } from "@/local-db/utils/utils";
|
||||
import { workItemSortWithOrderByExtended } from "@/plane-web/store/issue/helpers/base-issue.store";
|
||||
// services
|
||||
import { CycleService } from "@/services/cycle.service";
|
||||
import { IssueArchiveService, IssueDraftService, IssueService } from "@/services/issue";
|
||||
@@ -1991,7 +1992,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
|
||||
);
|
||||
|
||||
default:
|
||||
return getIssueIds(array);
|
||||
return workItemSortWithOrderByExtended(array, key);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { enableStaticRendering } from "mobx-react";
|
||||
// plane imports
|
||||
import { FALLBACK_LANGUAGE, LANGUAGE_STORAGE_KEY } from "@plane/i18n";
|
||||
// plane web store
|
||||
import { CommandPaletteStore, ICommandPaletteStore } from "@/plane-web/store/command-palette.store";
|
||||
import { RootStore } from "@/plane-web/store/root.store";
|
||||
@@ -97,7 +99,7 @@ export class CoreRootStore {
|
||||
resetOnSignOut() {
|
||||
// handling the system theme when user logged out from the app
|
||||
localStorage.setItem("theme", "system");
|
||||
|
||||
localStorage.setItem(LANGUAGE_STORAGE_KEY, FALLBACK_LANGUAGE);
|
||||
this.router = new RouterStore();
|
||||
this.commandPalette = new CommandPaletteStore();
|
||||
this.instance = new InstanceStore();
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./values";
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./update";
|
||||
@@ -1 +0,0 @@
|
||||
export * from "ce/components/issue-types/values/update";
|
||||
@@ -0,0 +1 @@
|
||||
export * from "ce/components/issues/issue-details/additional-properties";
|
||||
@@ -0,0 +1 @@
|
||||
export * from "ce/store/issue/helpers/base-issue.store";
|
||||
Reference in New Issue
Block a user