feat(slack-integration-stub): Slack-Integration-Stub Card auf Integrations-Page [tsc:fail]
This commit is contained in:
parent
04a9f3e014
commit
b50cec4fe5
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"completed_features": [],
|
"completed_features": [],
|
||||||
"current_feature": "recurring-time-entries",
|
"current_feature": "slack-integration-stub",
|
||||||
"started_at": "2026-05-23T07:57:43.412201",
|
"started_at": "2026-05-23T07:57:43.412201",
|
||||||
"attempted_features": [
|
"attempted_features": [
|
||||||
"time-budget-per-project"
|
"time-budget-per-project",
|
||||||
|
"recurring-time-entries"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -2405,3 +2405,20 @@ src/index.ts(27,25): error TS2769: No overload matches this call.
|
|||||||
Overload 2 of 3, '(plugin: FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
|
Overload 2 of 3, '(plugin: FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
|
||||||
Argument of type 'Promise<FastifyMultipartPlugin>' is not assignable to parameter of type 'FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'.
|
Argument of type 'Promise<FastifyMultipartPlugin>' is not assignable to parameter of type 'FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'.
|
||||||
Type 'Promise<FastifyMultipartPlugin>' provides no match for the signature '(instance: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTy
|
Type 'Promise<FastifyMultipartPlugin>' provides no match for the signature '(instance: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTy
|
||||||
|
- `08:02:18` **INFO** Committed feature recurring-time-entries
|
||||||
|
- `08:02:18` **INFO** Pushed: rc=0
|
||||||
|
|
||||||
|
## Phase-3 Feature: slack-integration-stub (2026-05-23 08:02:18)
|
||||||
|
|
||||||
|
- `08:02:18` **INFO** Description: Slack-Integration-Stub Card auf Integrations-Page
|
||||||
|
- `08:02:18` **INFO** Generating apps/web/src/pages/Integrations.tsx (ERWEITERT — die bestehende Slack-Karte bekommt jetzt 'Configure'-Butto…)
|
||||||
|
- `08:03:38` **INFO** wrote 9473 chars in 80.3s (attempt 1)
|
||||||
|
- `08:03:38` **INFO** Running tsc --noEmit on api…
|
||||||
|
- `08:03:40` **WARN** tsc errors:
|
||||||
|
src/index.ts(27,25): error TS2769: No overload matches this call.
|
||||||
|
Overload 1 of 3, '(plugin: FastifyPluginCallback<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
|
||||||
|
Argument of type 'Promise<FastifyMultipartPlugin>' is not assignable to parameter of type 'FastifyPluginCallback<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'.
|
||||||
|
Type 'Promise<FastifyMultipartPlugin>' provides no match for the signature '(instance: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProvider>, opts: { ...; }, done: (err?: Error | undefined) => void): void'.
|
||||||
|
Overload 2 of 3, '(plugin: FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
|
||||||
|
Argument of type 'Promise<FastifyMultipartPlugin>' is not assignable to parameter of type 'FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'.
|
||||||
|
Type 'Promise<FastifyMultipartPlugin>' provides no match for the signature '(instance: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTy
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Link } from '@tanstack/react-router';
|
import { Link } from '@tanstack/react-router';
|
||||||
import {
|
import {
|
||||||
Slack,
|
Slack,
|
||||||
@ -7,7 +7,11 @@ import {
|
|||||||
Calendar,
|
Calendar,
|
||||||
Mail,
|
Mail,
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
Lock
|
Lock,
|
||||||
|
X,
|
||||||
|
Send,
|
||||||
|
Loader2,
|
||||||
|
CheckCircle2
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
interface Integration {
|
interface Integration {
|
||||||
@ -25,7 +29,7 @@ const INTEGRATIONS: Integration[] = [
|
|||||||
name: 'Slack',
|
name: 'Slack',
|
||||||
description: 'Get notifications and updates directly in your Slack channels.',
|
description: 'Get notifications and updates directly in your Slack channels.',
|
||||||
icon: Slack,
|
icon: Slack,
|
||||||
status: 'coming-soon',
|
status: 'available',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'discord',
|
id: 'discord',
|
||||||
@ -60,6 +64,40 @@ const INTEGRATIONS: Integration[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export default function IntegrationsPage() {
|
export default function IntegrationsPage() {
|
||||||
|
const [isSlackModalOpen, setIsSlackModalOpen] = useState(false);
|
||||||
|
const [webhookUrl, setWebhookUrl] = useState('');
|
||||||
|
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
||||||
|
|
||||||
|
const handleSaveSlack = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setStatus('loading');
|
||||||
|
// Simulate API call to save settings
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 800));
|
||||||
|
setStatus('success');
|
||||||
|
setTimeout(() => setStatus('idle'), 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTestSlack = async () => {
|
||||||
|
if (!webhookUrl) return;
|
||||||
|
setStatus('loading');
|
||||||
|
try {
|
||||||
|
const response = await fetch(webhookUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ text: 'Hello from EmberClone! 🚀' }),
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
setStatus('success');
|
||||||
|
} else {
|
||||||
|
setStatus('error');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setStatus('error');
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => setStatus('idle'), 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-6xl mx-auto p-6">
|
<div className="max-w-6xl mx-auto p-6">
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
@ -105,6 +143,14 @@ export default function IntegrationsPage() {
|
|||||||
>
|
>
|
||||||
Configure
|
Configure
|
||||||
</button>
|
</button>
|
||||||
|
) : integration.id === 'slack' ? (
|
||||||
|
<button
|
||||||
|
onClick={() => setIsSlackModalOpen(true)}
|
||||||
|
className="flex items-center justify-center w-full py-2 px-4 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-medium transition-colors group"
|
||||||
|
>
|
||||||
|
Configure
|
||||||
|
<ArrowRight size={16} className="ml-2 transition-transform group-hover:translate-x-1" />
|
||||||
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
to={integration.link || '/'}
|
to={integration.link || '/'}
|
||||||
@ -118,6 +164,78 @@ export default function IntegrationsPage() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{isSlackModalOpen && (
|
||||||
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/50 backdrop-blur-sm">
|
||||||
|
<div className="bg-white dark:bg-slate-800 w-full max-w-md rounded-2xl shadow-2xl border border-slate-200 dark:border-slate-700 overflow-hidden">
|
||||||
|
<div className="flex items-center justify-between p-6 border-b border-slate-200 dark:border-slate-700">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-2 bg-indigo-100 dark:bg-indigo-900/50 text-indigo-600 dark:text-indigo-400 rounded-lg">
|
||||||
|
<Slack size={20} />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-xl font-bold text-slate-900 dark:text-white">Slack Integration</h2>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setIsSlackModalOpen(false)}
|
||||||
|
className="p-2 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors"
|
||||||
|
>
|
||||||
|
<X size={20} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSaveSlack} className="p-6 space-y-6">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||||
|
Incoming Webhook URL
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="url"
|
||||||
|
required
|
||||||
|
placeholder="https://hooks.slack.com/services/..."
|
||||||
|
className="w-full px-4 py-2 rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 text-slate-900 dark:text-white focus:ring-2 focus:ring-indigo-500 outline-none transition-all"
|
||||||
|
value={webhookUrl}
|
||||||
|
onChange={(e) => setWebhookUrl(e.target.value)}
|
||||||
|
/>
|
||||||
|
<p className="mt-2 text-xs text-slate-500 dark:text-slate-400">
|
||||||
|
Create an Incoming Webhook in your Slack App settings to get this URL.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleTestSlack}
|
||||||
|
disabled={!webhookUrl || status === 'loading'}
|
||||||
|
className="flex-1 flex items-center justify-center gap-2 py-2 px-4 bg-slate-100 dark:bg-slate-700 hover:bg-slate-200 dark:hover:bg-slate-600 text-slate-700 dark:text-slate-200 rounded-lg text-sm font-medium transition-colors disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{status === 'loading' ? <Loader2 size={16} className="animate-spin" /> : <Send size={16} />}
|
||||||
|
Test Connection
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={status === 'loading'}
|
||||||
|
className="flex-1 py-2 px-4 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{status === 'loading' ? <Loader2 size={16} className="animate-spin mx-auto" /> : 'Save Settings'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{status === 'success' && (
|
||||||
|
<div className="flex items-center gap-2 p-3 bg-emerald-50 dark:bg-emerald-900/20 text-emerald-600 dark:text-emerald-400 rounded-lg text-sm font-medium">
|
||||||
|
<CheckCircle2 size={16} />
|
||||||
|
Successfully updated and tested!
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{status === 'error' && (
|
||||||
|
<div className="flex items-center gap-2 p-3 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-lg text-sm font-medium">
|
||||||
|
<X size={16} />
|
||||||
|
Failed to connect. Please check your URL.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user