diff --git a/app/controllers/api/control/track_cards_controller.rb b/app/controllers/api/control/track_cards_controller.rb
index fc45bc8..193bf3d 100644
--- a/app/controllers/api/control/track_cards_controller.rb
+++ b/app/controllers/api/control/track_cards_controller.rb
@@ -13,20 +13,24 @@ def index
.where('activation_at <= ?', ts)
.limit(10)
.order(activation_at: :desc)
- .map(&:as_json)
else
cards = [
- TrackCard.current_for(params[:track_slug])&.as_json,
- *TrackCard.where(track: params[:track_slug]).candidate.map(&:as_json),
+ TrackCard.current_for(params[:track_slug]),
+ *TrackCard.where(track: params[:track_slug]).candidate.to_a,
]
end
render(json: {
- track_cards: cards.compact,
+ track_cards: cards.compact.map { |_| _.as_json(control: true) },
})
end
def create
- TrackCard.create!(track_card_params)
+ track_card = TrackCard.new(track_card_params)
+
+ now = Time.now
+ track_card.activation_at = now if track_card.activation_at < now
+
+ track_card.save!
EmitIvsMetadataJob.perform_now
render(json: {ok: true}.to_json)
end
diff --git a/app/javascript/Api.ts b/app/javascript/Api.ts
index 4bf51fd..40f3601 100644
--- a/app/javascript/Api.ts
+++ b/app/javascript/Api.ts
@@ -316,7 +316,7 @@ export type Attendee = {
export type Conference = {
default_track: string;
track_order: TrackSlug[];
- tracks: { [key: string]: Track };
+ tracks: { [key: TrackSlug]: Track };
};
export type TrackSlug = string;
@@ -329,11 +329,11 @@ export type Track = {
card: TrackCard | null;
card_candidate: TrackCard | null;
spotlights: ChatSpotlight[];
- presences: { [key: string]: StreamPresence }; // key:kind
+ presences: { [key in TrackStreamKind]: StreamPresence }; // key:kind
viewerCount?: ViewerCount;
};
-export interface TrackCard extends TrackCardHeader, TrackCardContent {}
+export type TrackCard = TrackCardHeader & TrackCardContent;
export type TrackCardHeader = {
track: TrackSlug;
@@ -430,7 +430,7 @@ export type GetAppVersionResponse = {
release: string;
};
-export type ChatSessionTracksBag = { [key: string]: TrackChatInfo | null };
+export type ChatSessionTracksBag = { [key: TrackSlug]: TrackChatInfo | null };
export type GetChatSessionResponse = {
expiry: number;
diff --git a/app/javascript/ContentCopyIcon.tsx b/app/javascript/ContentCopyIcon.tsx
new file mode 100644
index 0000000..84be91f
--- /dev/null
+++ b/app/javascript/ContentCopyIcon.tsx
@@ -0,0 +1,13 @@
+// Material Icon: content-copy
+import { createIcon } from "@chakra-ui/icons";
+
+export const ContentCopyIcon = createIcon({
+ displayName: "ContentCopy",
+ viewBox: "0 0 24 24",
+ path: (
+ <>
+
+
+ >
+ ),
+});
diff --git a/app/javascript/ControlApi.tsx b/app/javascript/ControlApi.tsx
index b461fb1..9636c4d 100644
--- a/app/javascript/ControlApi.tsx
+++ b/app/javascript/ControlApi.tsx
@@ -45,8 +45,10 @@ export type ControlGetConferenceResponse = {
speakers: { [key: string]: ConferenceSpeaker };
};
+export type ControlTrackCard = TrackCard & { id: number };
+
export type ControlGetTrackCardsResponse = {
- track_cards: TrackCard[];
+ track_cards: ControlTrackCard[];
};
export type ControlListAttendeesResponse = {
@@ -121,6 +123,13 @@ export const ControlApi = {
return resp.json();
},
+ async deleteTrackCard(card: ControlTrackCard) {
+ const url = `/api/control/tracks/${encodeURIComponent(card.track)}/cards/${encodeURIComponent(card.id)}`;
+ const resp = await request(url, "DELETE", null, {});
+ mutate(`/api/control/tracks/${encodeURIComponent(card.track)}/cards`);
+ return resp.json();
+ },
+
useAttendeeList(query: string | null) {
return useSWR(
query !== null ? `/api/control/attendees?query=${encodeURIComponent(query)}` : null,
diff --git a/app/javascript/ControlStreamPresence.tsx b/app/javascript/ControlStreamPresence.tsx
index cc9b86c..81054f2 100644
--- a/app/javascript/ControlStreamPresence.tsx
+++ b/app/javascript/ControlStreamPresence.tsx
@@ -23,7 +23,7 @@ const ControlTrackCardForm = loadable(() => import("./ControlTrackCardForm"));
export type Props = {
track: Track;
-}
+};
export const ControlStreamPresence: React.FC = ({ track }) => {
// const { data: controlConferenceData } = ControlApi.useConference();
@@ -114,7 +114,8 @@ export const StreamPresenceBox: React.FC<{