changeLog sayfasına yönlendirme
This commit is contained in:
parent
df3294e02a
commit
23667314ee
15 changed files with 68 additions and 33 deletions
|
|
@ -2009,7 +2009,9 @@ konfigürasyonu ile üretilir.
|
||||||
`ChangeLogStartupService` uygulama açılışında tabloyu bu dosyayla eşitler. Dosya imaja
|
`ChangeLogStartupService` uygulama açılışında tabloyu bu dosyayla eşitler. Dosya imaja
|
||||||
**gömülmez**: api build context'i içindeyken her yeni tag Dockerfile'daki `COPY . .`
|
**gömülmez**: api build context'i içindeyken her yeni tag Dockerfile'daki `COPY . .`
|
||||||
katmanını geçersiz kılıp imajı gereksiz yere yeniden derletiyordu; artık kod değişmediyse
|
katmanını geçersiz kılıp imajı gereksiz yere yeniden derletiyordu; artık kod değişmediyse
|
||||||
imaj cache'ten gelir. Yeni sürüm için tag atıp deploy etmek yeterlidir. Notlar
|
imaj cache'ten gelir. Yeni sürüm için tag atıp deploy etmek yeterlidir: dosya değiştiyse
|
||||||
|
`app.sh` API'yi yeniden başlatır, çünkü imajı değişmeyen konteynere `up -d` dokunmaz ve
|
||||||
|
açılışta okunan dosya aksi hâlde tabloya hiç yansımazdı. Notlar
|
||||||
**annotated** tag mesajından okunur (`git tag -a 1.2.0 -m "..."`), her satır bir madde.
|
**annotated** tag mesajından okunur (`git tag -a 1.2.0 -m "..."`), her satır bir madde.
|
||||||
- **Tablo git tag listesinin aynasıdır:** yeni tag eklenir, mesajı düzeltilen tag güncellenir,
|
- **Tablo git tag listesinin aynasıdır:** yeni tag eklenir, mesajı düzeltilen tag güncellenir,
|
||||||
git'ten silinen tag tablodan da (hard delete ile) kaldırılır. Bu yüzden `Sas_H_ChangeLog`
|
git'ten silinen tag tablodan da (hard delete ile) kaldırılır. Bu yüzden `Sas_H_ChangeLog`
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,7 @@ Dev / Prod Ortam Makinalarında (imajları çeker, api ve ui konteynerlerini yer
|
||||||
`~/sozsoft-platform/configs/deployment/scripts/9-dev-deploy.sh` (dev)
|
`~/sozsoft-platform/configs/deployment/scripts/9-dev-deploy.sh` (dev)
|
||||||
`~/sozsoft-platform/configs/deployment/scripts/5-production-deploy.sh` (production)
|
`~/sozsoft-platform/configs/deployment/scripts/5-production-deploy.sh` (production)
|
||||||
İkisi de `scripts/deploy/app.sh {env}` çağırır: konteynerler önceden durdurulmaz, `pull` → `up -d`;
|
İkisi de `scripts/deploy/app.sh {env}` çağırır: konteynerler önceden durdurulmaz, `pull` → `up -d`;
|
||||||
|
`change-logs.json` değiştiyse (yeni tag) API ayrıca `restart` edilir, yoksa sürüm notu tabloya yansımaz;
|
||||||
UI'nin eski sürüm chunk'ları `ui-assets` volume'unda kalır (bkz. `ui/README.md` › Konteyner).
|
UI'nin eski sürüm chunk'ları `ui-assets` volume'unda kalır (bkz. `ui/README.md` › Konteyner).
|
||||||
|
|
||||||
### Migrator
|
### Migrator
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ git fetch --prune --prune-tags --tags --force && git pull
|
||||||
# gerekmez). `bash ...` ile çağrılır: depo Windows'tan yönetildiği için
|
# gerekmez). `bash ...` ile çağrılır: depo Windows'tan yönetildiği için
|
||||||
# çalıştırma biti kaybolunca "Permission denied" verip notları sessizce düşürüyordu.
|
# çalıştırma biti kaybolunca "Permission denied" verip notları sessizce düşürüyordu.
|
||||||
RELEASE_NOTES=~/sozsoft-platform/configs/change-logs/change-logs.json
|
RELEASE_NOTES=~/sozsoft-platform/configs/change-logs/change-logs.json
|
||||||
|
RELEASE_NOTES_BEFORE=$(md5sum "$RELEASE_NOTES" 2>/dev/null | cut -d' ' -f1)
|
||||||
bash ~/sozsoft-platform/configs/change-logs/generate-change-logs.sh
|
bash ~/sozsoft-platform/configs/change-logs/generate-change-logs.sh
|
||||||
|
|
||||||
# Dosya yoksa API açılışta "change-logs.json bulunamadı" uyarısı verir ve
|
# Dosya yoksa API açılışta "change-logs.json bulunamadı" uyarısı verir ve
|
||||||
|
|
@ -30,3 +31,11 @@ COMPOSE="docker compose -f docker-compose-app.yml -f docker-compose-app.${ENV}.y
|
||||||
$COMPOSE --profile api --profile ui pull
|
$COMPOSE --profile api --profile ui pull
|
||||||
$COMPOSE --profile api up -d --remove-orphans
|
$COMPOSE --profile api up -d --remove-orphans
|
||||||
$COMPOSE --profile ui up -d --remove-orphans
|
$COMPOSE --profile ui up -d --remove-orphans
|
||||||
|
|
||||||
|
# API sürüm notlarını yalnızca açılışta okur. Yalnızca tag eklenen deploy'da imaj
|
||||||
|
# değişmediği için `up -d` konteynere dokunmaz ve yeni sürüm veritabanına hiç
|
||||||
|
# yazılmazdı; dosya değiştiyse API yeniden başlatılır.
|
||||||
|
if [ "$RELEASE_NOTES_BEFORE" != "$(md5sum "$RELEASE_NOTES" | cut -d' ' -f1)" ]; then
|
||||||
|
echo "change-logs.json değişti, API yeniden başlatılıyor."
|
||||||
|
$COMPOSE --profile api restart api
|
||||||
|
fi
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@ kökünde mount edilir), `installPrompt.ts` (PWA kurulum teklifi).
|
||||||
bitene kadar kapanmaz; ilk kurulumda (controller yok) kapatılabilir.
|
bitene kadar kapanmaz; ilk kurulumda (controller yok) kapatılabilir.
|
||||||
4. **Sürüm numarası ve notlar backend'dedir** (`extraProperties.changeLogs`,
|
4. **Sürüm numarası ve notlar backend'dedir** (`extraProperties.changeLogs`,
|
||||||
`/api/app/change-log`); UI'da sürüm dosyası yoktur. Son görülen sürüm store'un `locale`
|
`/api/app/change-log`); UI'da sürüm dosyası yoktur. Son görülen sürüm store'un `locale`
|
||||||
diliminde tutulur, giriş sonrası changelog yönlendirmesi oradan okunur.
|
diliminde tutulur; sürüm değişince yazılan bayrağı `ProtectedRoute` okur ve oturum açık
|
||||||
|
kullanıcıyı (login şartı olmadan) `/admin/changeLog`'a yönlendirir, ekran bayrağı tüketir.
|
||||||
5. **Runtime cache.** Hash'li dosyalar cache-first (`sozsoft-assets-v1`, aktivasyonda
|
5. **Runtime cache.** Hash'li dosyalar cache-first (`sozsoft-assets-v1`, aktivasyonda
|
||||||
`warmup.json`'da olmayan eski chunk'lar silinir), DevExtreme temaları stale-while-revalidate,
|
`warmup.json`'da olmayan eski chunk'lar silinir), DevExtreme temaları stale-while-revalidate,
|
||||||
font/görsel cache-first. `/api`, `/connect`, `/swagger`, `/signalr`, `/hangfire` worker'a
|
font/görsel cache-first. `/api`, `/connect`, `/swagger`, `/signalr`, `/hangfire` worker'a
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@ import appConfig from '@/proxy/configs/app.config'
|
||||||
import { REDIRECT_URL_KEY } from '@/constants/app.constant'
|
import { REDIRECT_URL_KEY } from '@/constants/app.constant'
|
||||||
import { Navigate, Outlet, useLocation } from 'react-router-dom'
|
import { Navigate, Outlet, useLocation } from 'react-router-dom'
|
||||||
import useAuth from '@/utils/hooks/useAuth'
|
import useAuth from '@/utils/hooks/useAuth'
|
||||||
|
import { useStoreState } from '@/store'
|
||||||
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
||||||
const { unAuthenticatedEntryPath } = appConfig
|
const { unAuthenticatedEntryPath } = appConfig
|
||||||
|
|
||||||
const ProtectedRoute = () => {
|
const ProtectedRoute = () => {
|
||||||
const { authenticated } = useAuth()
|
const { authenticated } = useAuth()
|
||||||
|
const pendingChangelogVersion = useStoreState((state) => state.locale.pendingChangelogVersion)
|
||||||
|
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
|
||||||
|
|
@ -19,6 +22,14 @@ const ProtectedRoute = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Yeni sürüm görüldüyse kullanıcı önce değişiklikleri okur. Kapı girişte değil
|
||||||
|
// burada: oturumu açık olan kullanıcı güncellemeyi yenileme ile alır ve bir daha
|
||||||
|
// login olmaz; yalnızca girişe bağlı bir yönlendirme onu hiç yakalamıyordu.
|
||||||
|
// Bayrak ChangeLog ekranında tüketilir.
|
||||||
|
if (pendingChangelogVersion && location.pathname !== ROUTES_ENUM.protected.admin.changeLog) {
|
||||||
|
return <Navigate replace to={ROUTES_ENUM.protected.admin.changeLog} />
|
||||||
|
}
|
||||||
|
|
||||||
return <Outlet />
|
return <Outlet />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
18
ui/src/components/shared/PageModeBadge.tsx
Normal file
18
ui/src/components/shared/PageModeBadge.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { useConfig } from '@/components/ui/ConfigProvider'
|
||||||
|
|
||||||
|
// Sayfa başlığındaki görünüm/mod rozeti. Badge'in .badge sınıfı katmansız CSS'te sabit kırmızıdır
|
||||||
|
// (bildirim sayacı) ve utility sınıfları ezemez; renkler tema renginden gelir, sınıflar
|
||||||
|
// tailwind/index.css'teki @source inline listesinde üretilir.
|
||||||
|
const PageModeBadge = ({ content }: { content: string }) => {
|
||||||
|
const { themeColor } = useConfig()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={`rounded-full px-2 py-0.5 text-xs bg-${themeColor}-100 text-${themeColor}-700 dark:bg-${themeColor}-500/20 dark:text-${themeColor}-300`}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PageModeBadge
|
||||||
|
|
@ -7,7 +7,7 @@ export interface LocaleStoreModel {
|
||||||
currentLang: string
|
currentLang: string
|
||||||
currentUiVersion: string | undefined
|
currentUiVersion: string | undefined
|
||||||
currentTenantName?: string
|
currentTenantName?: string
|
||||||
/** Dolu ise kullanıcı bir sonraki girişinde ChangeLog ekranına yönlendirilir. */
|
/** Dolu ise oturum açık kullanıcı yönetim ekranlarına girerken ChangeLog'a yönlendirilir (`ProtectedRoute`). */
|
||||||
pendingChangelogVersion?: string
|
pendingChangelogVersion?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,8 +44,9 @@ export const localeModel: LocaleModel = {
|
||||||
* Backend'den gelen çalışan sürümü işler (application-configuration →
|
* Backend'den gelen çalışan sürümü işler (application-configuration →
|
||||||
* `extraProperties.changeLogs.uiVersion`).
|
* `extraProperties.changeLogs.uiVersion`).
|
||||||
*
|
*
|
||||||
* Sürüm son görülenden farklıysa changelog bayrağı yazılır; kullanıcı bir
|
* Sürüm son görülenden farklıysa changelog bayrağı yazılır; oturum açık kullanıcı
|
||||||
* sonraki girişinde ChangeLog ekranına yönlendirilir. Tetikleyici bilerek
|
* yönetim ekranlarına ilk girişinde (`ProtectedRoute`) ChangeLog'a yönlendirilir —
|
||||||
|
* login şartı yoktur, güncellemeyi yenilemeyle alan açık oturum da yakalanır. Tetikleyici bilerek
|
||||||
* bundle değil sürümdür: yalnızca yeni bir git tag'i eklendiğinde de kullanıcı
|
* bundle değil sürümdür: yalnızca yeni bir git tag'i eklendiğinde de kullanıcı
|
||||||
* değişiklikleri görür.
|
* değişiklikleri görür.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { jwtDecode } from '@/utils/jwt'
|
import { jwtDecode } from '@/utils/jwt'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import useQuery from './useQuery'
|
import useQuery from './useQuery'
|
||||||
import { store, useStoreActions, useStoreState } from '../../store/store'
|
import { useStoreActions, useStoreState } from '../../store/store'
|
||||||
import {
|
import {
|
||||||
FailedSignInResponse,
|
FailedSignInResponse,
|
||||||
SignInCredential,
|
SignInCredential,
|
||||||
|
|
@ -13,7 +13,6 @@ import { isLoginSuccess } from '../../proxy/account/models'
|
||||||
import { REDIRECT_URL_KEY } from '../../constants/app.constant'
|
import { REDIRECT_URL_KEY } from '../../constants/app.constant'
|
||||||
import appConfig from '../../proxy/configs/app.config'
|
import appConfig from '../../proxy/configs/app.config'
|
||||||
import { register } from '../../services/account.service'
|
import { register } from '../../services/account.service'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
|
||||||
|
|
||||||
type Status = 'success' | 'failed' | 'error'
|
type Status = 'success' | 'failed' | 'error'
|
||||||
|
|
||||||
|
|
@ -68,17 +67,8 @@ function useAuth() {
|
||||||
} = resp.data
|
} = resp.data
|
||||||
handleToken({ token, refreshToken, expiresIn })
|
handleToken({ token, refreshToken, expiresIn })
|
||||||
|
|
||||||
const redirectUrl = query.get(REDIRECT_URL_KEY)
|
// Bekleyen changelog yönlendirmesi ProtectedRoute'tadır; giriş hedefi değişmez.
|
||||||
// Uygulama yeni bir sürümle/deploy ile açıldıysa kullanıcı önce
|
navigate(query.get(REDIRECT_URL_KEY) ?? appConfig.authenticatedEntryPath)
|
||||||
// değişiklikleri görsün. Bayrak ChangeLog ekranında tüketilir.
|
|
||||||
//
|
|
||||||
// Değer hook state'inden değil doğrudan store'dan okunur: bayrak giriş
|
|
||||||
// sayfasındaki config yüklemesiyle yazılıyor, render kapanışı bayat
|
|
||||||
// kalabilir.
|
|
||||||
const target = store.getState().locale.pendingChangelogVersion
|
|
||||||
? ROUTES_ENUM.protected.admin.changeLog
|
|
||||||
: (redirectUrl ?? appConfig.authenticatedEntryPath)
|
|
||||||
navigate(target)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: 'success',
|
status: 'success',
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import Td from '@/components/ui/Table/Td'
|
||||||
import Th from '@/components/ui/Table/Th'
|
import Th from '@/components/ui/Table/Th'
|
||||||
import Tr from '@/components/ui/Table/Tr'
|
import Tr from '@/components/ui/Table/Tr'
|
||||||
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
|
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
|
||||||
import { useStoreState } from '@/store'
|
import { useListFormValues } from './listFormDraftContext'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { FaEdit, FaFileMedical, FaTrash } from 'react-icons/fa'
|
import { FaEdit, FaFileMedical, FaTrash } from 'react-icons/fa'
|
||||||
|
|
@ -19,7 +19,7 @@ function FormTabCommands() {
|
||||||
const [jsonRowOpModalData, setJsonRowOpModalData] = useState<JsonRowDialogData>()
|
const [jsonRowOpModalData, setJsonRowOpModalData] = useState<JsonRowDialogData>()
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const initialValues = useStoreState((s) => s.admin.lists.values)
|
const initialValues = useListFormValues()
|
||||||
if (!initialValues) {
|
if (!initialValues) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import Td from '@/components/ui/Table/Td'
|
||||||
import Th from '@/components/ui/Table/Th'
|
import Th from '@/components/ui/Table/Th'
|
||||||
import Tr from '@/components/ui/Table/Tr'
|
import Tr from '@/components/ui/Table/Tr'
|
||||||
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
|
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
|
||||||
import { useStoreState } from '@/store'
|
import { useListFormValues } from './listFormDraftContext'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { FaEdit, FaFileMedical, FaTrash } from 'react-icons/fa'
|
import { FaEdit, FaFileMedical, FaTrash } from 'react-icons/fa'
|
||||||
|
|
@ -18,7 +18,7 @@ function FormTabExtraFilters(props: { listFormCode: string }) {
|
||||||
const [jsonRowOpModalData, setJsonRowOpModalData] = useState<JsonRowDialogData>()
|
const [jsonRowOpModalData, setJsonRowOpModalData] = useState<JsonRowDialogData>()
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const initialValues = useStoreState((s) => s.admin.lists.values)
|
const initialValues = useListFormValues()
|
||||||
if (!initialValues) {
|
if (!initialValues) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button, Checkbox, Dialog, FormItem, Input, Select, Tabs } from '@/components/ui'
|
import { Button, Checkbox, Dialog, FormItem, Input, Select, Tabs } from '@/components/ui'
|
||||||
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
|
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
|
||||||
import { SelectBoxOption } from '@/types/shared'
|
import { SelectBoxOption } from '@/types/shared'
|
||||||
import { useStoreState } from '@/store'
|
import { useListFormValues } from '../listFormDraftContext'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { Field, FieldProps, Form, Formik } from 'formik'
|
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||||
import { Dispatch, SetStateAction } from 'react'
|
import { Dispatch, SetStateAction } from 'react'
|
||||||
|
|
@ -39,7 +39,7 @@ function JsonRowOpDialogAnnotation({
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
const rows = useJsonRowOps()
|
const rows = useJsonRowOps()
|
||||||
|
|
||||||
const listFormValues = useStoreState((s) => s.admin.lists.values)
|
const listFormValues = useListFormValues()
|
||||||
if (!listFormValues) {
|
if (!listFormValues) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button, Card, Checkbox, Dialog, FormItem, Input, Select } from '@/components/ui'
|
import { Button, Card, Checkbox, Dialog, FormItem, Input, Select } from '@/components/ui'
|
||||||
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
|
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
|
||||||
import { SelectBoxOption } from '@/types/shared'
|
import { SelectBoxOption } from '@/types/shared'
|
||||||
import { useStoreState } from '@/store'
|
import { useListFormValues } from '../listFormDraftContext'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { Field, FieldProps, Form, Formik } from 'formik'
|
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||||
import { Dispatch, SetStateAction } from 'react'
|
import { Dispatch, SetStateAction } from 'react'
|
||||||
|
|
@ -85,7 +85,7 @@ function JsonRowOpDialogSeries({
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const listFormValues = useStoreState((s) => s.admin.lists.values)
|
const listFormValues = useListFormValues()
|
||||||
if (!listFormValues) {
|
if (!listFormValues) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ import type { ReactNode, RefObject } from 'react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { FaInfoCircle } from 'react-icons/fa'
|
import { FaInfoCircle } from 'react-icons/fa'
|
||||||
import { Container, Loading } from '@/components/shared'
|
import { Container, Loading } from '@/components/shared'
|
||||||
import { Badge, Dialog } from '@/components/ui'
|
import { Dialog } from '@/components/ui'
|
||||||
|
import PageModeBadge from '@/components/shared/PageModeBadge'
|
||||||
import RichText from '@/components/shared/RichText'
|
import RichText from '@/components/shared/RichText'
|
||||||
import type { GridDto } from '@/proxy/form/models'
|
import type { GridDto } from '@/proxy/form/models'
|
||||||
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
||||||
|
|
@ -121,14 +122,14 @@ export const FormPageShell = ({
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setDescriptionOpen(true)}
|
onClick={() => setDescriptionOpen(true)}
|
||||||
>
|
>
|
||||||
<h4 className="text-slate-700 text-sm font-medium leading-none">{title}</h4>
|
<h4 className="text-sm font-medium leading-none">{title}</h4>
|
||||||
<FaInfoCircle className="text-xs opacity-60" />
|
<FaInfoCircle className="text-xs opacity-60" />
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<h4 className="text-slate-700 text-sm font-medium leading-none">{title}</h4>
|
<h4 className="text-sm font-medium leading-none">{title}</h4>
|
||||||
)}
|
)}
|
||||||
●
|
●
|
||||||
<Badge content={mode} />
|
<PageModeBadge content={mode} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ import { useParams, useSearchParams } from 'react-router-dom'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import Container from '@/components/shared/Container'
|
import Container from '@/components/shared/Container'
|
||||||
import { Badge, Button, Dialog } from '@/components/ui'
|
import { Button, Dialog } from '@/components/ui'
|
||||||
|
import PageModeBadge from '@/components/shared/PageModeBadge'
|
||||||
import RichText from '@/components/shared/RichText'
|
import RichText from '@/components/shared/RichText'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
||||||
|
|
@ -245,7 +246,7 @@ const List: React.FC<ListProps> = ({
|
||||||
) : (
|
) : (
|
||||||
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
||||||
)}
|
)}
|
||||||
<Badge content={viewMode} />
|
<PageModeBadge content={viewMode} />
|
||||||
|
|
||||||
{/* =======================
|
{/* =======================
|
||||||
VIEW BUTTONS
|
VIEW BUTTONS
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ const Changelog = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Bekleyen changelog bayrağı burada tüketilir; kullanıcı değişiklikleri
|
// Bekleyen changelog bayrağı burada tüketilir; kullanıcı değişiklikleri
|
||||||
// gördüğü için sonraki girişlerde tekrar yönlendirilmez.
|
// gördüğü için ProtectedRoute bir daha buraya yönlendirmez.
|
||||||
clearPendingChangelog()
|
clearPendingChangelog()
|
||||||
|
|
||||||
void changeLogService
|
void changeLogService
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue