fix: temporarily lock tasker dark theme
This commit is contained in:
@@ -9,7 +9,7 @@ import { observer } from "mobx-react";
|
||||
import { useTheme } from "next-themes";
|
||||
// plane imports
|
||||
import type { I_THEME_OPTION } from "@plane/constants";
|
||||
import { THEME_OPTIONS } from "@plane/constants";
|
||||
import { NODEDC_FORCED_THEME, NODEDC_THEME_LOCK_ENABLED, THEME_OPTIONS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { setPromiseToast } from "@plane/propel/toast";
|
||||
// components
|
||||
@@ -34,15 +34,16 @@ export const ThemeSwitcher = observer(function ThemeSwitcher(props: {
|
||||
const { t } = useTranslation();
|
||||
// derived values
|
||||
const currentTheme = useMemo(() => {
|
||||
const userThemeOption = THEME_OPTIONS.find((t) => t.value === userProfile?.theme?.theme);
|
||||
return userThemeOption || null;
|
||||
const themeValue = NODEDC_THEME_LOCK_ENABLED ? NODEDC_FORCED_THEME : userProfile?.theme?.theme;
|
||||
return THEME_OPTIONS.find((themeOption) => themeOption.value === themeValue) || null;
|
||||
}, [userProfile?.theme?.theme]);
|
||||
|
||||
const handleThemeChange = useCallback(
|
||||
(themeOption: I_THEME_OPTION) => {
|
||||
try {
|
||||
setTheme(themeOption.value);
|
||||
const updatePromise = updateUserTheme({ theme: themeOption.value });
|
||||
const nextTheme = NODEDC_THEME_LOCK_ENABLED ? NODEDC_FORCED_THEME : themeOption.value;
|
||||
setTheme(nextTheme);
|
||||
const updatePromise = updateUserTheme({ theme: nextTheme });
|
||||
setPromiseToast(updatePromise, {
|
||||
loading: "Updating theme...",
|
||||
success: {
|
||||
@@ -58,7 +59,7 @@ export const ThemeSwitcher = observer(function ThemeSwitcher(props: {
|
||||
console.error("Error updating theme:", error);
|
||||
}
|
||||
},
|
||||
[updateUserTheme]
|
||||
[setTheme, updateUserTheme]
|
||||
);
|
||||
|
||||
if (!userProfile) return null;
|
||||
@@ -70,7 +71,7 @@ export const ThemeSwitcher = observer(function ThemeSwitcher(props: {
|
||||
description={t(props.option.description)}
|
||||
control={<ThemeSwitch value={currentTheme} onChange={handleThemeChange} />}
|
||||
/>
|
||||
{userProfile.theme?.theme === "custom" && <CustomThemeSelector />}
|
||||
{!NODEDC_THEME_LOCK_ENABLED && userProfile.theme?.theme === "custom" && <CustomThemeSelector />}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
// plane imports
|
||||
import type { I_THEME_OPTION } from "@plane/constants";
|
||||
import { THEME_OPTIONS } from "@plane/constants";
|
||||
import { NODEDC_ACTIVE_THEME_OPTIONS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// constants
|
||||
import { SelectionDropdown } from "@/components/common/selection-dropdown";
|
||||
@@ -17,34 +17,34 @@ type Props = {
|
||||
onChange: (value: I_THEME_OPTION) => void;
|
||||
};
|
||||
|
||||
const renderThemeSwatch = (themeOption: I_THEME_OPTION) => (
|
||||
<div
|
||||
className="relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border-1"
|
||||
style={{
|
||||
borderColor: themeOption.icon.border,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-l-full"
|
||||
style={{
|
||||
background: themeOption.icon.color1,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-r-full border-l"
|
||||
style={{
|
||||
borderLeftColor: themeOption.icon.border,
|
||||
background: themeOption.icon.color2,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
export function ThemeSwitch(props: Props) {
|
||||
const { value, onChange } = props;
|
||||
// translation
|
||||
const { t } = useTranslation();
|
||||
|
||||
const renderThemeSwatch = (themeOption: I_THEME_OPTION) => (
|
||||
<div
|
||||
className="relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border-1"
|
||||
style={{
|
||||
borderColor: themeOption.icon.border,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-l-full"
|
||||
style={{
|
||||
background: themeOption.icon.color1,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-r-full border-l"
|
||||
style={{
|
||||
borderLeftColor: themeOption.icon.border,
|
||||
background: themeOption.icon.color2,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<SelectionDropdown
|
||||
placement="bottom-end"
|
||||
@@ -59,7 +59,7 @@ export function ThemeSwitch(props: Props) {
|
||||
)
|
||||
}
|
||||
menuButtonWrapperClassName="flex w-full items-center justify-between rounded-full border border-subtle-1 px-3 py-2 text-13"
|
||||
options={THEME_OPTIONS.map((themeOption) => ({
|
||||
options={NODEDC_ACTIVE_THEME_OPTIONS.map((themeOption) => ({
|
||||
key: themeOption.value,
|
||||
isChecked: value?.value === themeOption.value,
|
||||
onClick: () => onChange(themeOption),
|
||||
|
||||
@@ -9,6 +9,7 @@ import React, { useState } from "react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { ArrowRightLeft } from "lucide-react";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { NODEDC_FORCED_THEME, NODEDC_THEME_LOCK_ENABLED } from "@plane/constants";
|
||||
// ui
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
@@ -42,9 +43,10 @@ export function SwitchAccountModal(props: Props) {
|
||||
|
||||
await signOut()
|
||||
.then(() => {
|
||||
setTheme("system");
|
||||
setTheme(NODEDC_THEME_LOCK_ENABLED ? NODEDC_FORCED_THEME : "system");
|
||||
router.push("/");
|
||||
handleClose();
|
||||
return undefined;
|
||||
})
|
||||
.catch(() =>
|
||||
setToast({
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useCallback } from "react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Calendar, Earth, Languages, Palette } from "lucide-react";
|
||||
// plane imports
|
||||
import { NODEDC_FORCED_THEME, NODEDC_THEME_LOCK_ENABLED } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { setToast, TOAST_TYPE } from "@plane/propel/toast";
|
||||
import type { EStartOfTheWeek, TUserProfile } from "@plane/types";
|
||||
@@ -29,8 +30,9 @@ export const usePowerKPreferencesCommands = (): TPowerKCommandConfig[] => {
|
||||
|
||||
const handleUpdateTheme = useCallback(
|
||||
async (newTheme: string) => {
|
||||
setTheme(newTheme);
|
||||
return updateUserTheme({ theme: newTheme })
|
||||
const nextTheme = NODEDC_THEME_LOCK_ENABLED ? NODEDC_FORCED_THEME : newTheme;
|
||||
setTheme(nextTheme);
|
||||
return updateUserTheme({ theme: nextTheme })
|
||||
.then(() => {
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
|
||||
@@ -8,7 +8,7 @@ import React, { useEffect, useState } from "react";
|
||||
import { Command } from "cmdk";
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
import { THEME_OPTIONS } from "@plane/constants";
|
||||
import { NODEDC_ACTIVE_THEME_OPTIONS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// local imports
|
||||
import { PowerKModalCommandItem } from "../../modal/command-item";
|
||||
@@ -33,7 +33,7 @@ export const PowerKPreferencesThemesMenu = observer(function PowerKPreferencesTh
|
||||
|
||||
return (
|
||||
<Command.Group>
|
||||
{THEME_OPTIONS.map((theme) => (
|
||||
{NODEDC_ACTIVE_THEME_OPTIONS.map((theme) => (
|
||||
<PowerKModalCommandItem key={theme.value} onSelect={() => onSelect(theme.value)} label={t(theme.i18n_label)} />
|
||||
))}
|
||||
</Command.Group>
|
||||
|
||||
@@ -137,7 +137,10 @@ export const CodexAgentApiSettingsContent = observer(function CodexAgentApiSetti
|
||||
})
|
||||
)
|
||||
);
|
||||
const workspaceProjectGroups = projectAccessPayload?.workspaces ?? [];
|
||||
const workspaceProjectGroups = useMemo(
|
||||
() => projectAccessPayload?.workspaces ?? [],
|
||||
[projectAccessPayload?.workspaces]
|
||||
);
|
||||
const projectOptions = useMemo(() => flattenProjectAccessOptions(workspaceProjectGroups), [workspaceProjectGroups]);
|
||||
const effectiveSelectedProjectKey = selectedProjectKey || projectOptions[0]?.key || "";
|
||||
const setupCards = useMemo(
|
||||
@@ -735,6 +738,10 @@ function CodexConnectionGuide(props: TCodexConnectionGuideProps) {
|
||||
В строке <code>Authorization</code> замените только <code>ВАШ_УНИКАЛЬНЫЙ_ТОКЕН</code> на значение из{" "}
|
||||
<code>Agent token</code>. <code>Bearer</code> и <code>ndcag_</code> оставьте как есть.
|
||||
</p>
|
||||
<p className="mt-3">
|
||||
Не используйте <code>bearer_token_env_var</code>, если переменная окружения не добавлена в macOS launchd:
|
||||
Codex Desktop не увидит обычный <code>export</code> из shell-профиля.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="nodedc-settings-input min-h-36 px-4 py-4 text-13 leading-5 text-secondary">
|
||||
@@ -743,6 +750,10 @@ function CodexConnectionGuide(props: TCodexConnectionGuideProps) {
|
||||
Сохраните <code>config.toml</code> и перезапустите локальный Codex. После старта попросите Codex проверить
|
||||
доступные проекты через <code>tasker_list_projects</code>.
|
||||
</p>
|
||||
<p className="mt-3">
|
||||
Если токен или endpoint временно недоступны, чат Codex все равно откроется, но MCP tools появятся только
|
||||
после исправления подключения.
|
||||
</p>
|
||||
<p className="mt-3">Правила работы и grants Codex получит сам через MCP по токену.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -775,13 +786,13 @@ function buildCodexConfigSnippet(endpoint: string): string {
|
||||
return `[mcp_servers.${CODEX_MCP_SERVER_NAME}]
|
||||
url = "${endpoint}"
|
||||
enabled = true
|
||||
required = true
|
||||
required = false
|
||||
startup_timeout_sec = 20
|
||||
tool_timeout_sec = 60
|
||||
|
||||
[mcp_servers.${CODEX_MCP_SERVER_NAME}.headers]
|
||||
Authorization = "Bearer ndcag_ВАШ_УНИКАЛЬНЫЙ_ТОКЕН"
|
||||
Accept = "application/json, text/event-stream"
|
||||
Accept = "application/json"
|
||||
"MCP-Protocol-Version" = "2025-06-18"`;
|
||||
}
|
||||
|
||||
@@ -995,6 +1006,7 @@ function mergeTokens(primaryTokens: TCodexAgentToken[], secondaryTokens: TCodexA
|
||||
const tokensById = new Map<string, TCodexAgentToken>();
|
||||
for (const token of primaryTokens) tokensById.set(token.id, token);
|
||||
for (const token of secondaryTokens) tokensById.set(token.id, tokensById.get(token.id) ?? token);
|
||||
// oxlint-disable-next-line unicorn/no-array-sort
|
||||
return Array.from(tokensById.values()).sort(
|
||||
(leftToken, rightToken) => new Date(rightToken.created_at).getTime() - new Date(leftToken.created_at).getTime()
|
||||
);
|
||||
@@ -1072,13 +1084,16 @@ function buildProjectGrantPayload(grantKeys: string[]): { workspace_slug: string
|
||||
}
|
||||
|
||||
function getGrantedProjectKeys(grants: TCodexAgentGrant[]): string[] {
|
||||
return [
|
||||
const grantedProjectKeys = [
|
||||
...new Set(
|
||||
grants
|
||||
.filter((grant) => grant.project_id)
|
||||
.map((grant) => buildProjectGrantKey(grant.workspace_slug, String(grant.project_id)))
|
||||
),
|
||||
].sort();
|
||||
];
|
||||
|
||||
// oxlint-disable-next-line unicorn/no-array-sort
|
||||
return grantedProjectKeys.sort();
|
||||
}
|
||||
|
||||
type TMergeAgentGrantsOptions = {
|
||||
|
||||
Reference in New Issue
Block a user