mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 12:43:58 +00:00
Merge branch 'feature/dynamic-promo-widget'
This commit is contained in:
@@ -8,6 +8,7 @@ const {
|
|||||||
getCloudContent,
|
getCloudContent,
|
||||||
putCloudContent,
|
putCloudContent,
|
||||||
removeCloudCachedConnection,
|
removeCloudCachedConnection,
|
||||||
|
getPromoWidgetData,
|
||||||
} = require('../utility/cloudIntf');
|
} = require('../utility/cloudIntf');
|
||||||
const connections = require('./connections');
|
const connections = require('./connections');
|
||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
@@ -283,6 +284,18 @@ module.exports = {
|
|||||||
return getAiGatewayServer();
|
return getAiGatewayServer();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
premiumPromoWidget_meta: true,
|
||||||
|
async premiumPromoWidget() {
|
||||||
|
const data = getPromoWidgetData();
|
||||||
|
if (data?.state != 'data') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (data.validTo && new Date().getTime() > new Date(data.validTo).getTime()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
// chatStream_meta: {
|
// chatStream_meta: {
|
||||||
// raw: true,
|
// raw: true,
|
||||||
// method: 'post',
|
// method: 'post',
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const currentVersion = require('../currentVersion');
|
|||||||
const logger = getLogger('cloudIntf');
|
const logger = getLogger('cloudIntf');
|
||||||
|
|
||||||
let cloudFiles = null;
|
let cloudFiles = null;
|
||||||
|
let promoWidgetData = null;
|
||||||
|
|
||||||
const DBGATE_IDENTITY_URL = process.env.LOCAL_DBGATE_IDENTITY
|
const DBGATE_IDENTITY_URL = process.env.LOCAL_DBGATE_IDENTITY
|
||||||
? 'http://localhost:3103'
|
? 'http://localhost:3103'
|
||||||
@@ -259,6 +260,36 @@ async function getPublicFileData(path) {
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updatePremiumPromoWidget() {
|
||||||
|
try {
|
||||||
|
const fileContent = await fs.readFile(path.join(datadir(), 'promo-widget.json'), 'utf-8');
|
||||||
|
promoWidgetData = JSON.parse(fileContent);
|
||||||
|
} catch (err) {
|
||||||
|
promoWidgetData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = (await collectCloudFilesSearchTags()).join(',');
|
||||||
|
|
||||||
|
const resp = await axios.default.get(
|
||||||
|
`${DBGATE_CLOUD_URL}/premium-promo-widget?identifier=${promoWidgetData?.identifier ?? 'empty'}&tags=${tags}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
...(await getCloudInstanceHeaders()),
|
||||||
|
'x-app-version': currentVersion.version,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!resp.data || resp.data?.state == 'unchanged') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
promoWidgetData = resp.data;
|
||||||
|
await fs.writeFile(path.join(datadir(), 'promo-widget.json'), JSON.stringify(promoWidgetData, null, 2));
|
||||||
|
|
||||||
|
socket.emitChanged(`promo-widget-changed`);
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshPublicFiles(isRefresh) {
|
async function refreshPublicFiles(isRefresh) {
|
||||||
if (!cloudFiles) {
|
if (!cloudFiles) {
|
||||||
await loadCloudFiles();
|
await loadCloudFiles();
|
||||||
@@ -268,6 +299,9 @@ async function refreshPublicFiles(isRefresh) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(extractErrorLogData(err), 'DBGM-00166 Error updating cloud files');
|
logger.error(extractErrorLogData(err), 'DBGM-00166 Error updating cloud files');
|
||||||
}
|
}
|
||||||
|
if (!isProApp()) {
|
||||||
|
await updatePremiumPromoWidget();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function callCloudApiGet(endpoint, signinHolder = null, additionalHeaders = {}) {
|
async function callCloudApiGet(endpoint, signinHolder = null, additionalHeaders = {}) {
|
||||||
@@ -432,6 +466,10 @@ async function getPublicIpInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPromoWidgetData() {
|
||||||
|
return promoWidgetData;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createDbGateIdentitySession,
|
createDbGateIdentitySession,
|
||||||
startCloudTokenChecking,
|
startCloudTokenChecking,
|
||||||
@@ -449,4 +487,5 @@ module.exports = {
|
|||||||
readCloudTokenHolder,
|
readCloudTokenHolder,
|
||||||
readCloudTestTokenHolder,
|
readCloudTestTokenHolder,
|
||||||
getPublicIpInfo,
|
getPublicIpInfo,
|
||||||
|
getPromoWidgetData,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ export const focusedConnectionOrDatabase = writable<{ conid: string; database?:
|
|||||||
export const focusedTreeDbKey = writable<{ key: string; root: string; type: string; text: string }>(null);
|
export const focusedTreeDbKey = writable<{ key: string; root: string; type: string; text: string }>(null);
|
||||||
|
|
||||||
export const cloudSigninTokenHolder = writableSettingsValue(null, 'cloudSigninTokenHolder');
|
export const cloudSigninTokenHolder = writableSettingsValue(null, 'cloudSigninTokenHolder');
|
||||||
|
export const seenPremiumPromoWidget = writableWithStorage(null, 'seenPremiumPromoWidget');
|
||||||
|
|
||||||
export const cloudConnectionsStore = writable({});
|
export const cloudConnectionsStore = writable({});
|
||||||
|
|
||||||
|
|||||||
@@ -183,12 +183,16 @@ const cloudContentListLoader = () => ({
|
|||||||
params: {},
|
params: {},
|
||||||
reloadTrigger: { key: `cloud-content-changed` },
|
reloadTrigger: { key: `cloud-content-changed` },
|
||||||
});
|
});
|
||||||
|
|
||||||
const teamFilesLoader = () => ({
|
const teamFilesLoader = () => ({
|
||||||
url: 'team-files/list',
|
url: 'team-files/list',
|
||||||
params: {},
|
params: {},
|
||||||
reloadTrigger: { key: `team-files-changed` },
|
reloadTrigger: { key: `team-files-changed` },
|
||||||
});
|
});
|
||||||
|
const promoWidgetLoader = () => ({
|
||||||
|
url: 'cloud/premium-promo-widget',
|
||||||
|
params: {},
|
||||||
|
reloadTrigger: { key: `promo-widget-changed` },
|
||||||
|
});
|
||||||
|
|
||||||
async function getCore(loader, args) {
|
async function getCore(loader, args) {
|
||||||
const { url, params, reloadTrigger, transform, onLoaded, errorValue } = loader(args);
|
const { url, params, reloadTrigger, transform, onLoaded, errorValue } = loader(args);
|
||||||
@@ -536,3 +540,10 @@ export function getTeamFiles(args) {
|
|||||||
export function useTeamFiles(args) {
|
export function useTeamFiles(args) {
|
||||||
return useCore(teamFilesLoader, args);
|
return useCore(teamFilesLoader, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPromoWidget(args) {
|
||||||
|
return getCore(promoWidgetLoader, args);
|
||||||
|
}
|
||||||
|
export function usePromoWidget(args) {
|
||||||
|
return useCore(promoWidgetLoader, args);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,59 +1,15 @@
|
|||||||
<script lang='ts'>
|
<script lang="ts">
|
||||||
import JsonUiContentRenderer from '../jsonui/JsonUiContentRenderer.svelte';
|
import JsonUiContentRenderer from '../jsonui/JsonUiContentRenderer.svelte';
|
||||||
import { JsonUiBlock } from '../jsonui/jsonuitypes';
|
import { usePromoWidget } from '../utility/metadataLoaders';
|
||||||
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
|
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
|
||||||
|
|
||||||
const data: JsonUiBlock[] = [
|
const promoWidget = usePromoWidget({});
|
||||||
{ type: 'heading', text: 'Try DbGate Premium' },
|
|
||||||
{ type: 'text', text: 'Upgrade to get exclusive features:' },
|
|
||||||
{
|
|
||||||
type: 'ticklist',
|
|
||||||
items: [
|
|
||||||
'Query designer',
|
|
||||||
'AI powered database chat',
|
|
||||||
'Unlimited DbGate Cloud storage',
|
|
||||||
'Shared cloud folders',
|
|
||||||
'Charts from query result',
|
|
||||||
'Compare database models',
|
|
||||||
'Synchronize database structure',
|
|
||||||
'Backup & restore database',
|
|
||||||
'Advanced ER diagram settings',
|
|
||||||
'Export database model',
|
|
||||||
'Firestore, libSQL, Turso, CosmosDB, Redshift support',
|
|
||||||
'Amazon and Azure identity providers',
|
|
||||||
'E-mail support',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
{ type: 'heading', text: 'Download DbGate Premium' },
|
|
||||||
{
|
|
||||||
type: 'ticklist',
|
|
||||||
items: ['Free 30 day trial', 'DbGate Premium will reuse your connections and files from DbGate Community'],
|
|
||||||
},
|
|
||||||
{ type: 'button', text: 'Download', link: 'https://www.dbgate.io/download' },
|
|
||||||
|
|
||||||
{ type: 'heading', text: 'Purchase DbGate Premium' },
|
|
||||||
{
|
|
||||||
type: 'ticklist',
|
|
||||||
items: ['Use monthly or yearly subscription'],
|
|
||||||
},
|
|
||||||
{ type: 'button', text: 'Purchase', link: 'https://www.dbgate.io/purchase/premium' },
|
|
||||||
|
|
||||||
{ type: 'heading', text: 'Get PREMIUM license for free' },
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
text: 'Your feedback is very valuable for us. We have time-limited offers available for users who provide feedback.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'button',
|
|
||||||
text: 'View current offer',
|
|
||||||
link: 'https://www.dbgate.io/review?utm_campaign=communityWidget',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<WidgetsInnerContainer>
|
<WidgetsInnerContainer>
|
||||||
<JsonUiContentRenderer blocks={data} />
|
{#if $promoWidget?.state == 'data'}
|
||||||
|
<JsonUiContentRenderer blocks={$promoWidget?.blocks} />
|
||||||
|
{/if}
|
||||||
</WidgetsInnerContainer>
|
</WidgetsInnerContainer>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
lockedDatabaseMode,
|
lockedDatabaseMode,
|
||||||
getCurrentConfig,
|
getCurrentConfig,
|
||||||
cloudSigninTokenHolder,
|
cloudSigninTokenHolder,
|
||||||
|
seenPremiumPromoWidget,
|
||||||
} from '../stores';
|
} from '../stores';
|
||||||
import mainMenuDefinition from '../../../../app/src/mainMenuDefinition';
|
import mainMenuDefinition from '../../../../app/src/mainMenuDefinition';
|
||||||
import hasPermission from '../utility/hasPermission';
|
import hasPermission from '../utility/hasPermission';
|
||||||
@@ -20,11 +21,14 @@
|
|||||||
import { showModal } from '../modals/modalTools';
|
import { showModal } from '../modals/modalTools';
|
||||||
import NewObjectModal from '../modals/NewObjectModal.svelte';
|
import NewObjectModal from '../modals/NewObjectModal.svelte';
|
||||||
import openNewTab from '../utility/openNewTab';
|
import openNewTab from '../utility/openNewTab';
|
||||||
|
import { usePromoWidget } from '../utility/metadataLoaders';
|
||||||
|
|
||||||
let domSettings;
|
let domSettings;
|
||||||
let domCloudAccount;
|
let domCloudAccount;
|
||||||
let domMainMenu;
|
let domMainMenu;
|
||||||
|
|
||||||
|
const promoWidget = usePromoWidget({});
|
||||||
|
|
||||||
const widgets = [
|
const widgets = [
|
||||||
getCurrentConfig().storageDatabase && {
|
getCurrentConfig().storageDatabase && {
|
||||||
icon: 'icon admin',
|
icon: 'icon admin',
|
||||||
@@ -98,6 +102,10 @@
|
|||||||
} else {
|
} else {
|
||||||
$selectedWidget = name;
|
$selectedWidget = name;
|
||||||
$visibleWidgetSideBar = true;
|
$visibleWidgetSideBar = true;
|
||||||
|
|
||||||
|
if (name == 'premium') {
|
||||||
|
$seenPremiumPromoWidget = $promoWidget?.identifier || '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//const handleChangeWidget= e => (selectedWidget.set(item.name))
|
//const handleChangeWidget= e => (selectedWidget.set(item.name))
|
||||||
@@ -169,7 +177,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{#each widgets
|
{#each widgets
|
||||||
.filter(x => x && hasPermission(`widgets/${x.name}`))
|
.filter(x => x && hasPermission(`widgets/${x.name}`))
|
||||||
.filter(x => !x.isPremiumPromo || !isProApp())
|
.filter(x => !x.isPremiumPromo || (!isProApp() && $promoWidget?.state == 'data'))
|
||||||
// .filter(x => !x.isPremiumOnly || isProApp())
|
// .filter(x => !x.isPremiumOnly || isProApp())
|
||||||
.filter(x => x.name != 'cloud-private' || $cloudSigninTokenHolder) as item}
|
.filter(x => x.name != 'cloud-private' || $cloudSigninTokenHolder) as item}
|
||||||
<div
|
<div
|
||||||
@@ -181,6 +189,9 @@
|
|||||||
<FontIcon icon={item.icon} title={item.title} />
|
<FontIcon icon={item.icon} title={item.title} />
|
||||||
{#if item.isPremiumPromo}
|
{#if item.isPremiumPromo}
|
||||||
<div class="premium-promo">Premium</div>
|
<div class="premium-promo">Premium</div>
|
||||||
|
{#if $promoWidget?.identifier != $seenPremiumPromoWidget}
|
||||||
|
<div class="premium-promo-not-seen">•</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -262,4 +273,12 @@
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.premium-promo-not-seen {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 16pt;
|
||||||
|
color: var(--theme-icon-yellow);
|
||||||
|
top: -5px;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user